// One entropy generator: RINGS ring oscillators whose enhanced outputs are each sampled // every clock and XORed together (spatial XOR, pipelined), then XORed over `temporal` // consecutive clocks. The output bit is held for `temporal` clocks, so capturing it with // decimation = temporal yields every output bit exactly once. // // XOR combining multiplies the relative predictabilities (2P-1) of independent inputs, so // the ring count and temporal factor set the residual bias and correlation of the output. // // A selected ring's sampled outputs and its raw tap are exposed for characterization. module entropy_generator #( parameter RINGS = 90 // at most 256 (four 4:1 XOR stages) ) ( input wire clk, input wire enable, // low stops all rings input wire [3:0] temporal, // consecutive bits XORed per output bit, 1-8 input wire [7:0] ring_select, // ring exposed on the characterization outputs output reg out_bit, // processed output, held for `temporal` clocks output reg out_valid, // pulse: out_bit has just been updated output wire spatial_bit, // XOR of all rings, one per clock output wire [RINGS-1:0] ring_samples, // synchronized enhanced outputs, for health tests output reg ring_enhanced, output reg ring_tap, output wire ring_raw_tap // unsynchronized, for frequency counting ); wire [RINGS-1:0] raw_enhanced, raw_tap; genvar i; generate for (i = 0; i < RINGS; i = i + 1) begin : ring ring_osc #(.LENGTH(9 + 3 * (i % 3))) osc ( .enable(enable), .first_tap(raw_tap[i]), .enhanced(raw_enhanced[i]) ); end endgenerate // sample_raw catches the asynchronous ring signals and may go metastable; // sample_sync resolves it. The SDC file cuts timing into sample_raw. reg [RINGS-1:0] sample_raw, sample_sync, tap_raw, tap_sync; always @(posedge clk) begin sample_raw <= raw_enhanced; sample_sync <= sample_raw; tap_raw <= raw_tap; tap_sync <= tap_raw; end // Spatial XOR: four registered stages of 4-input XORs (256 -> 64 -> 16 -> 4 -> 1). reg [255:0] level0; reg [63:0] level1; reg [15:0] level2; reg [3:0] level3; reg level4; integer j; always @(*) begin level0 = 256'd0; level0[RINGS-1:0] = sample_sync; end always @(posedge clk) begin for (j = 0; j < 64; j = j + 1) level1[j] <= ^level0[4*j +: 4]; for (j = 0; j < 16; j = j + 1) level2[j] <= ^level1[4*j +: 4]; for (j = 0; j < 4; j = j + 1) level3[j] <= ^level2[4*j +: 4]; level4 <= ^level3; end assign spatial_bit = level4; assign ring_samples = sample_sync; // Temporal XOR over `temporal` consecutive spatial bits. reg [3:0] phase = 4'd0; reg accumulator = 1'b0; wire last = (phase >= temporal - 4'd1) || (temporal == 4'd0); always @(posedge clk) begin out_valid <= last; if (last) begin out_bit <= accumulator ^ spatial_bit; accumulator <= 1'b0; phase <= 4'd0; end else begin accumulator <= accumulator ^ spatial_bit; phase <= phase + 4'd1; end end // Characterization taps always @(posedge clk) begin ring_enhanced <= sample_sync[ring_select]; ring_tap <= tap_sync[ring_select]; end assign ring_raw_tap = raw_tap[ring_select]; endmodule