blob: b6bd1cb95d58ea8e9157524be72f2e51092f5c5a [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//############################################################################
// *Name: entropy
// *Module Description: Entropy
//############################################################################
`timescale 1ns / 10ps
module entropy #(
parameter int EntropyRateWidth = 4
) (
input edn_pkg::edn_rsp_t entropy_rsp_i, // Entropy Response
input [EntropyRateWidth-1:0] entropy_rate_i, // Entropy Rate
input clk_ast_es_i, // Entropy Clock
input rst_ast_es_ni, // Entropy Reset
input clk_src_sys_en_i, // System Source Clock Enable
input clk_src_sys_jen_i, // System Source Clock Jitter Enable
output edn_pkg::edn_req_t entropy_req_o // Entropy Request
);
///////////////////////////////////////
// Entropy Enable
///////////////////////////////////////
// Entropy Logic @clk_ast_es_i clock domain
// Reset De-Assert syncronizer
logic entropy_enable, sync_rst_es_n, rst_es_n;
assign entropy_enable = (rst_ast_es_ni && clk_src_sys_en_i && clk_src_sys_jen_i);
prim_generic_flop_2sync #(
.Width ( 1 )
) rst_es_da_sync (
.clk_i ( clk_ast_es_i ),
.rst_ni ( entropy_enable ),
.d_i ( 1'b1 ),
.q_o ( sync_rst_es_n )
);
assign rst_es_n = sync_rst_es_n;
///////////////////////////////////////
// Entropy Rate
///////////////////////////////////////
logic read_entropy, fast_start;
logic [(1<<EntropyRateWidth)-1:0] erate_cnt;
logic [32-1:0] entropy_rate;
logic [6-1:0] fast_cnt;
logic inc_fifo_cnt, dec_fifo_cnt;
always_ff @( posedge clk_ast_es_i, negedge rst_es_n ) begin
if ( !rst_es_n ) erate_cnt <= {(1<<EntropyRateWidth){1'b0}};
else if ( read_entropy ) erate_cnt <= {(1<<EntropyRateWidth){1'b0}};
else erate_cnt <= erate_cnt + 1'b1;
end
always_ff @( posedge clk_ast_es_i, negedge rst_es_n ) begin
if ( !rst_es_n ) begin
fast_start <= 1'b1;
fast_cnt <= 6'h00;
end
else if ( fast_cnt == 6'h20 )
fast_start <= 1'b0;
else if ( fast_start && dec_fifo_cnt )
fast_cnt <= fast_cnt + 1'b1;
end
assign entropy_rate = fast_start ? 1 : (1 << entropy_rate_i);
assign read_entropy = (entropy_rate == 1) || (erate_cnt == entropy_rate[(1<<EntropyRateWidth)-1:0]);
///////////////////////////////////////
// Entropy FIFO
///////////////////////////////////////
//
// 64-bit FIFO
// 32 +----------------------------------------+ 1
// edn_bus =/=>|+--------------------+ +---------------+|-/-> To LFSR
// edn_ack --->|| 32-bit prim_packer |-| 32 1-bit fifo ||---> valid (!empty)
// edn_req <---|+--------------------+ +---------------+|<--- read_entropy
// +----------------------------------------+
//
// The FIFO level should be calculated by (32*n - bits_to_LFSR)
// A request will be issue when the 32-bit buffer is empty!
// That means, the FIFO level <= 31 (?Air? bubble cleared from the fifo)
// So, making sure the req_o is/was issued when the FIFO level < 16 will be true at all time.
// FIFO RDP/WRP/Level
logic [6-1:0] fifo_cnt; // For 32 1-bit FIFO
logic [5-1:0] fifo_rdp, fifo_wrp; // FIFO read pointer & write pointer
logic [32-1:0] fifo_data; // 32 1-bit FIFO
logic fifo_full, fifo_empty;
logic entropy_req, entropy_ack, entropy_bit, entropy_bit_valid;
logic [6-1:0] entropy_depth_o;
logic [32-1:0] entropy_bus;
assign entropy_req_o.edn_req = entropy_req;
assign entropy_ack = entropy_rsp_i.edn_ack;
assign entropy_bus = entropy_rsp_i.edn_bus;
prim_packer_fifo #(
.InW ( 32 ),
.OutW ( 1 )
) u_pached_fifo (
.clk_i ( clk_ast_es_i ),
.rst_ni ( rst_es_n ),
.clr_i ( 1'b0 ), // Not used
.wvalid_i ( entropy_ack ), // EDN_ACK
.wdata_i ( entropy_bus ), // EDN_BUS (32-bit)
.wready_o ( entropy_req ), // EDN_REQ
//
.rvalid_o ( entropy_bit_valid ), // Entropy bit is valid
.rdata_o ( entropy_bit ), // Entropy bit
.rready_i ( !fifo_full ), // FIFO is not full
.depth_o ( entropy_depth_o[6-1:0] ) // empty when (entropy_depth_o == `0)
);
assign fifo_full = (fifo_cnt == 6'h20);
assign fifo_empty = (fifo_cnt == 6'h00);
assign inc_fifo_cnt = !fifo_full && entropy_bit_valid;
assign dec_fifo_cnt = !fifo_empty && read_entropy;
always_ff @( posedge clk_ast_es_i, negedge rst_es_n ) begin
if ( !rst_es_n ) begin
fifo_cnt <= 6'h00;
fifo_rdp <= 5'h00;
fifo_wrp <= 5'h00;
end
else if ( inc_fifo_cnt && dec_fifo_cnt ) begin
fifo_rdp <= fifo_rdp + 1'b1;
fifo_wrp <= fifo_wrp + 1'b1;
end
else if ( inc_fifo_cnt ) begin
fifo_cnt <= fifo_cnt + 1'b1;
fifo_wrp <= fifo_wrp + 1'b1;
end
else if ( dec_fifo_cnt ) begin
fifo_cnt <= fifo_cnt - 1'b1;
fifo_rdp <= fifo_rdp + 1'b1;
end
end
// FIFO Write
always_ff @( posedge clk_ast_es_i, negedge rst_es_n ) begin
if ( !rst_es_n ) fifo_data[32-1:0] <= {32{1'b0}};
else if ( inc_fifo_cnt ) fifo_data[fifo_wrp] <= entropy_bit;
end
// FIFO Read Out
wire fifo_entropy_out = fifo_data[fifo_rdp];
endmodule // of entropy