blob: 647669380459881e335114be489b8895706d4e44 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Description: entropy_src Markov health test module
//
module entropy_src_markov_ht #(
parameter int RegWidth = 16,
parameter int RngBusWidth = 4
) (
input logic clk_i,
input logic rst_ni,
// ins req interface
input logic [RngBusWidth-1:0] entropy_bit_i,
input logic entropy_bit_vld_i,
input logic clear_i,
input logic active_i,
input logic [RegWidth-1:0] thresh_hi_i,
input logic [RegWidth-1:0] thresh_lo_i,
input logic window_wrap_pulse_i,
input logic threshold_scope_i,
output logic [RegWidth-1:0] test_cnt_hi_o,
output logic [RegWidth-1:0] test_cnt_lo_o,
output logic test_fail_hi_pulse_o,
output logic test_fail_lo_pulse_o,
output logic count_err_o
);
// signals
logic [RngBusWidth-1:0] samples_no_match_pulse;
logic [RegWidth-1:0] pair_cntr_max;
logic [RegWidth-1:0] pair_cntr_min, pair_cntr_min_tmp;
logic [RegWidth-1:0] pair_cntr_sum;
logic [RngBusWidth-1:0][RegWidth-1:0] pair_cntr;
logic [RngBusWidth-1:0] pair_cntr_err;
// flops
logic toggle_q, toggle_d;
logic [RngBusWidth-1:0] prev_sample_q, prev_sample_d;
always_ff @(posedge clk_i or negedge rst_ni)
if (!rst_ni) begin
toggle_q <= '0;
prev_sample_q <= '0;
end else begin
toggle_q <= toggle_d;
prev_sample_q <= prev_sample_d;
end
// Markov Test
//
// Test operation
// This test will look at pairs of bit levels per bitstream. A counter for
// stream will only count when the pair equals 0b01 or 0b10.
for (genvar sh = 0; sh < RngBusWidth; sh = sh+1) begin : gen_cntrs
// bit sampler
assign prev_sample_d[sh] = (!active_i || clear_i) ? '0 :
window_wrap_pulse_i ? '0 :
entropy_bit_vld_i ? entropy_bit_i[sh] :
prev_sample_q[sh];
// pair check
assign samples_no_match_pulse[sh] = entropy_bit_vld_i && toggle_q &&
(prev_sample_q[sh] == !entropy_bit_i[sh]);
// pair counter
prim_count #(
.Width(RegWidth)
) u_prim_count_pair_cntr (
.clk_i,
.rst_ni,
.clr_i(window_wrap_pulse_i),
.set_i(!active_i || clear_i),
.set_cnt_i(RegWidth'(0)),
.incr_en_i(samples_no_match_pulse[sh]),
.decr_en_i(1'b0),
.step_i(RegWidth'(1)),
.cnt_o(pair_cntr[sh]),
.cnt_next_o(),
.err_o(pair_cntr_err[sh])
);
end : gen_cntrs
// create a toggle signal to sample pairs with
assign toggle_d = (!active_i || clear_i) ? '0 :
window_wrap_pulse_i ? '0 :
entropy_bit_vld_i ? (!toggle_q) :
toggle_q;
// determine the highest counter pair counter value
prim_max_tree #(
.NumSrc(RngBusWidth),
.Width(RegWidth)
) u_max (
.clk_i (clk_i),
.rst_ni (rst_ni),
.values_i (pair_cntr),
.valid_i ({RngBusWidth{1'b1}}),
.max_value_o (pair_cntr_max),
.max_idx_o (),
.max_valid_o ()
);
// determine the lowest counter pair counter value
// Negate the inputs and outputs of prim_max_tree to find the minimum
// For this unsigned application, one's complement negation (i.e. logical inversion) is fine.
prim_max_tree #(
.NumSrc(RngBusWidth),
.Width(RegWidth)
) u_min (
.clk_i (clk_i),
.rst_ni (rst_ni),
.values_i (~pair_cntr),
.valid_i ({RngBusWidth{1'b1}}),
.max_value_o (pair_cntr_min_tmp),
.max_idx_o (),
.max_valid_o ()
);
// Invert the output back.
assign pair_cntr_min = ~pair_cntr_min_tmp;
prim_sum_tree #(
.NumSrc(RngBusWidth),
.Width(RegWidth)
) u_sum (
.clk_i (clk_i),
.rst_ni (rst_ni),
.values_i (pair_cntr),
.valid_i ({RngBusWidth{1'b1}}),
.sum_value_o (pair_cntr_sum),
.sum_valid_o ()
);
assign test_cnt_hi_o = threshold_scope_i ? pair_cntr_sum : pair_cntr_max;
assign test_cnt_lo_o = threshold_scope_i ? pair_cntr_sum : pair_cntr_min;
// the pulses will be only one clock in length
assign test_fail_hi_pulse_o = active_i && window_wrap_pulse_i && (test_cnt_hi_o > thresh_hi_i);
assign test_fail_lo_pulse_o = active_i && window_wrap_pulse_i && (test_cnt_lo_o < thresh_lo_i);
assign count_err_o = (|pair_cntr_err);
endmodule