// Byte stream of entropy for the SAMD21: bits from the selected channel (optionally through a // von Neumann extractor) are packed MSB first into bytes and queued in a FIFO. When the FIFO // is full, new bytes are dropped and counted; bits are never reused. // // Reading: `head` is the oldest byte, valid while `available`; `pop` removes it. A popped // byte's successor appears on `head` two cycles later. `level` and `available` are registered // and lag by a cycle, which only ever understates what can be read. module entropy_stream #( parameter ADDR_WIDTH = 12 // 4096-byte FIFO ) ( input wire clk, input wire reset, input wire flush, input wire bit_in, input wire valid, input wire von_neumann, input wire pop, output reg [7:0] head, output reg available, output reg [ADDR_WIDTH:0] level, output reg [15:0] dropped // bytes dropped since flush, saturating ); // Von Neumann (01 -> 0, 10 -> 1) reg pair_first, have_first; wire vn_valid = von_neumann ? (valid && have_first && bit_in != pair_first) : valid; wire vn_bit = von_neumann ? pair_first : bit_in; always @(posedge clk) begin if (reset || flush || !von_neumann) begin have_first <= 1'b0; end else if (valid) begin have_first <= ~have_first; pair_first <= bit_in; end end // Packing reg [6:0] partial; reg [2:0] bit_count; reg byte_ready; reg [7:0] byte_out; always @(posedge clk) begin byte_ready <= 1'b0; if (reset || flush) begin bit_count <= 3'd0; end else if (vn_valid) begin partial <= {partial[5:0], vn_bit}; bit_count <= bit_count + 3'd1; if (bit_count == 3'd7) begin byte_ready <= 1'b1; byte_out <= {partial, vn_bit}; end end end // FIFO reg [7:0] buffer [0:(1 << ADDR_WIDTH) - 1]; reg [ADDR_WIDTH:0] write_ptr, read_ptr; wire [ADDR_WIDTH:0] fill = write_ptr - read_ptr; wire full = fill[ADDR_WIDTH]; always @(posedge clk) begin if (reset || flush) begin write_ptr <= {(ADDR_WIDTH + 1){1'b0}}; read_ptr <= {(ADDR_WIDTH + 1){1'b0}}; dropped <= 16'd0; end else begin if (byte_ready) begin if (!full) begin buffer[write_ptr[ADDR_WIDTH-1:0]] <= byte_out; write_ptr <= write_ptr + 1'b1; end else if (dropped != 16'hFFFF) begin dropped <= dropped + 16'd1; end end if (pop && fill != 0) read_ptr <= read_ptr + 1'b1; end head <= buffer[read_ptr[ADDR_WIDTH-1:0]]; level <= fill; available <= fill != 0 && !(pop && fill == 1); end endmodule