blob: cd6ef378a1f2a4ea39e0eef94b23b237f54c9e7a [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 system verilog unit test bench
// The intent of this test bench is to get basics running,
// such as clocks and reset, basic register writes and reads,
// basic block operation. No configurable BFMs are included
// in this environment.
module entropy_src_tb;
import tlul_pkg::*;
import entropy_src_reg_pkg::*;
// tests
bit smoke_test = 0;
bit interrupt_test = 0;
bit lfsr_update_test = 0;
bit basic_entropy_test = 0;
bit stress_test = 1;
// options
bit msg_rd_data = 0;
// parameters`
localparam EsFifoDepth = 32;
localparam MAX_INTRP_CNT = 25;
localparam WD_DELAY = 1000*MAX_INTRP_CNT;
// general signals
logic clk;
logic rst_n;
logic es_entropy_valid_o;
logic es_entropy_fifo_err_o;
// tlul signals
tlul_pkg::tl_h2d_t tl_i;
tlul_pkg::tl_d2h_t tl_o;
// imported register parameters (for reference)
// Register Address
// parameter ENTROPY_SRC_INTR_STATE_OFFSET = 6'h 0;
// parameter ENTROPY_SRC_INTR_ENABLE_OFFSET = 6'h 4;
// parameter ENTROPY_SRC_INTR_TEST_OFFSET = 6'h 8;
// parameter ENTROPY_SRC_ES_REGEN_OFFSET = 6'h c;
// parameter ENTROPY_SRC_ES_CONF_OFFSET = 6'h 10;
// parameter ENTROPY_SRC_ES_REV_OFFSET = 6'h 14;
// parameter ENTROPY_SRC_ES_ENTROPY_OFFSET = 6'h 1c;
// parameter ENTROPY_SRC_ES_CTRL_OFFSET = 6'h 20;
// parameter ENTROPY_SRC_ES_STATUS_OFFSET = 6'h 24;
// parameter ENTROPY_SRC_ES_FDEPTHST_OFFSET = 6'h 28;
// parameter ENTROPY_SRC_ES_THRESH_OFFSET = 6'h 2c;
// parameter ENTROPY_SRC_ES_RATE_OFFSET = 6'h 30;
// parameter ENTROPY_SRC_ES_SEED_OFFSET = 6'h 34;
//---------------------------
// testbench support
//---------------------------
bit errflag = 0;
logic [31:0] rd_data = 0;
logic [31:0] thresh_level = 0;
logic [31:0] entropy_rate = 0;
logic [31:0] fifo_depth = 0;
logic [31:0] intrp_cnt = 0;
initial
begin // initial values
clk = 0;
rst_n = 0;
tl_i.a_valid = 0;
tl_i.a_address = 0;
tl_i.a_opcode = PutFullData; // write as default
tl_i.a_param = 3'h0;
tl_i.a_size = 2'h0;
tl_i.a_source = 8'h0;
tl_i.a_user = 0;
tl_i.a_mask = 0;
tl_i.a_data = 0;
tl_i.d_ready =1;
end
initial // clock generation
begin
clk = 0;
forever begin
#4ns clk = !clk;
end
end
initial // reset generation
begin
repeat (4) @ (posedge clk);
rst_n = 1;
end
initial // watchdog
begin
repeat (WD_DELAY) @ (posedge clk);
$display("%t %c[1;31mEntropy_Src watchdog triggered - FAIL!!! %c[0m",$time,27,27);
$finish;
end
task wr_reg(input logic [31:0] addr, logic [31:0] wdata);
repeat (1) @ (posedge clk); #1ps;
while (tl_o.a_ready != 1) begin
repeat (1) @ (posedge clk); #1ps;
end
tl_i.a_valid =1;
tl_i.a_address = addr;
tl_i.a_opcode = PutFullData; // write = 0
tl_i.a_param = 3'h0;
tl_i.a_size = 2'h2;
tl_i.a_source = 8'h0;
tl_i.a_mask = 4'hf;
tl_i.a_data = wdata;
repeat (1) @ (posedge clk); #1ps;
tl_i.a_valid = 0;
tl_i.a_address = 0;
tl_i.a_opcode = PutFullData; // write as default
tl_i.a_param = 3'h0;
tl_i.a_size = 2'h0;
tl_i.a_source = 8'h0;
tl_i.a_mask = 0;
tl_i.a_data = 0;
repeat (1) @ (posedge clk); #1ps;
endtask
task rd_reg(input logic [31:0] addr, output logic [31:0] rdata);
repeat (1) @ (posedge clk); #1ps;
tl_i.d_ready =1;
while (tl_o.a_ready != 1) begin
repeat (1) @ (posedge clk); #1ps;
end
tl_i.a_valid =1;
tl_i.a_address = addr;
tl_i.a_opcode = Get; // read = 4
tl_i.a_param = 3'h0;
tl_i.a_size = 2'h2;
tl_i.a_source = 8'h0;
tl_i.a_mask = 4'hf;
while (tl_o.d_valid != 1) begin
repeat (1) @ (posedge clk); #1ps;
end
tl_i.a_valid = 0;
tl_i.d_ready = 1;
tl_i.a_address = 0;
tl_i.a_opcode = PutFullData; // write as default
tl_i.a_param = 3'h0;
tl_i.a_size = 2'h0;
tl_i.a_source = 8'h0;
tl_i.a_mask = 0;
tl_i.a_data = 0;
rdata = tl_o.d_data;
if (msg_rd_data) $display("%t rdata = %h",$time,rdata);
repeat (1) @ (posedge clk); #1ps;
endtask
task cmp_reg(input logic [31:0] addr, logic [31:0] cdata, logic [31:0] cmask);
logic [31:0] rdata;
rd_reg(addr,rdata);
if ((rdata & cmask) !== cdata) begin
$display("%t reg addr: %h",$time,addr);
$display("%t act raw data: %h",$time,rdata);
$display("%t exp mask data: %h",$time,(rdata & cmask));
$display("%t exp data: %h",$time,cdata);
$display("%t %c[1;31mRead register miscompare!!! %c[0m",$time,27,27);
$finish;
// errflag = 1;
end
endtask
task test_end(input bit errflag);
cmp_reg(ENTROPY_SRC_ES_STATUS_OFFSET,32'h0000_0000,32'hffff_ffff);
if (errflag == 1) begin
$display("%t %c[1;31mEntropy_Src Test FAIL!!! %c[0m",$time,27,27);
end else begin
$display("%t %c[1;32mEntropy_Src Test PASSED... %c[0m",$time,27,27);
end
$finish;
endtask
always @ (posedge es_entropy_valid_o) // interrupt handler
begin
if (rst_n) begin // handle reset case
if (stress_test) begin
rd_data = 0;
for (int i=0; i < thresh_level; i=i+1) begin
rd_reg({26'b0,ENTROPY_SRC_ES_ENTROPY_OFFSET},rd_data);
end
repeat (1) @ (posedge clk); #1ps;
// reset interrupt
wr_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h0000_0001);
if (es_entropy_valid_o !== 0) begin
$display("%t %c[1;31mInterrupt did not reset FAIL!!! %c[0m",$time,27,27);
$finish;
end
// randomly change entropy_rate
void'(randomize (entropy_rate) with { entropy_rate inside {[3:30]};});
$display("%t Interrupt entropy_rate = %h ",$time,entropy_rate);
wr_reg({26'b0,ENTROPY_SRC_ES_RATE_OFFSET},(entropy_rate)); // rate
intrp_cnt++;
$display("%t Interrupt intrp_cnt = %h ",$time,intrp_cnt);
end
end
end
//-------------------------------------
// testcases
//-------------------------------------
initial begin
while (rst_n !== 1'b1) begin // avoid initial x case
repeat (1) @ (posedge clk); #1ps;
end
repeat (10) @ (posedge clk); #1ps;
// Comon register setup
// -> placeholder
repeat (20) @ (posedge clk); #1ps;
//-----------------------------------------------------
if (smoke_test) begin
$display("%t Running smoke_test...",$time);
cmp_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h1234_5678,32'hffff_ffff);
wr_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'habdc_efab); // wr config reg
cmp_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'habdc_efab,32'hffff_ffff);
cmp_reg({26'b0,ENTROPY_SRC_ES_REV_OFFSET},32'h0001_0201,32'hffff_ffff);
end
//-----------------------------------------------------
if (interrupt_test) begin
$display("%t Running interrupt_test...",$time);
wr_reg({26'b0,ENTROPY_SRC_INTR_ENABLE_OFFSET},32'h0000_0003); // enable intrs
cmp_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h000000000,32'hffff_ffff); // check to see that interrupts are off
// test intrp 0
wr_reg({26'b0,ENTROPY_SRC_INTR_TEST_OFFSET},32'h0000_0001);
cmp_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h000000001,32'hffff_ffff); // check interrupt state
wr_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h0000_0001);
cmp_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h000000000,32'hffff_ffff); // check to see that interrupts are off
// test intrp 1
wr_reg({26'b0,ENTROPY_SRC_INTR_TEST_OFFSET},32'h0000_0002);
cmp_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h000000002,32'hffff_ffff); // check interrupt state
wr_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h0000_0002);
cmp_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h000000000,32'hffff_ffff); // check to see that interrupts are off
end
//-----------------------------------------------------
if (lfsr_update_test) begin
$display("%t Running lfsr_update_test...",$time);
wr_reg({26'b0,ENTROPY_SRC_ES_RATE_OFFSET},32'h0000_0001); // rate
wr_reg({26'b0,ENTROPY_SRC_ES_THRESH_OFFSET},32'h0000_0001); // thresh level
wr_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h1111_1111); // seed
wr_reg({26'b0,ENTROPY_SRC_ES_CONF_OFFSET},32'h0000_0001); // primary enable
repeat (10) @ (posedge clk);
wr_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h2222_2222); // change seed, should not write since fifo is not full
wr_reg({26'b0,ENTROPY_SRC_ES_CTRL_OFFSET},32'h0000_0001); // init bit on
wr_reg({26'b0,ENTROPY_SRC_ES_CTRL_OFFSET},32'h0000_0000); // init bit off
repeat (30) @ (posedge clk);
cmp_reg({26'b0,ENTROPY_SRC_ES_FDEPTHST_OFFSET},32'h000000020,32'hffff_ffff); // check to see if FIFO is full
wr_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h3333_3333); // change seed, should write since init bit is on
wr_reg({26'b0,ENTROPY_SRC_ES_CTRL_OFFSET},32'h0000_0001); // init bit on
wr_reg({26'b0,ENTROPY_SRC_ES_CTRL_OFFSET},32'h0000_0000); // init bit off
repeat (10) @ (posedge clk);
wr_reg({26'b0,ENTROPY_SRC_ES_REGEN_OFFSET},32'h0000_0001); // clear write enable register, make it off
wr_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h4444_4444); // change seed, should not write since lock seed bit is on
cmp_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h3333_3333,32'hffff_ffff); // check to see that seed did not change
wr_reg({26'b0,ENTROPY_SRC_ES_CTRL_OFFSET},32'h0000_0001); // init bit on
wr_reg({26'b0,ENTROPY_SRC_ES_CTRL_OFFSET},32'h0000_0000); // init bit off
repeat (5) @ (posedge clk);
// set entropy to off
wr_reg({26'b0,ENTROPY_SRC_ES_RATE_OFFSET},32'h0000_0000); // rate turned off
// drain the fifo
for (int i=0; i < 32; i=i+1) begin
rd_reg({26'b0,ENTROPY_SRC_ES_ENTROPY_OFFSET},rd_data);
end
// clear any interrupts
wr_reg({26'b0,ENTROPY_SRC_INTR_STATE_OFFSET},32'h0000_0003);
end
//-----------------------------------------------------
if (basic_entropy_test) begin
$display("%t Running basic_entropy_test...",$time);
thresh_level = 32'h0000_000f;
wr_reg({26'b0,ENTROPY_SRC_INTR_ENABLE_OFFSET},32'h0000_0003); // enable intrs
wr_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h2345_3456); // seed
wr_reg({26'b0,ENTROPY_SRC_ES_RATE_OFFSET},32'h0000_0008); // rate
wr_reg({26'b0,ENTROPY_SRC_ES_THRESH_OFFSET},thresh_level); // thresh level
wr_reg({26'b0,ENTROPY_SRC_ES_CONF_OFFSET},32'h0000_0001); // primary enable
// read out entropy
rd_data = 0;
repeat (20) @ (posedge clk);
while (rd_data < thresh_level) begin
rd_reg({26'b0,ENTROPY_SRC_ES_FDEPTHST_OFFSET},rd_data);
end
// set entropy to super slow
wr_reg({26'b0,ENTROPY_SRC_ES_RATE_OFFSET},32'h0000_ffff); // rate
for (int i=0; i < thresh_level; i=i+1) begin
rd_reg({26'b0,ENTROPY_SRC_ES_ENTROPY_OFFSET},rd_data);
end
rd_reg({26'b0,ENTROPY_SRC_ES_FDEPTHST_OFFSET},fifo_depth);
// drain the rest of the fifo
for (int i=0; i < fifo_depth; i=i+1) begin
rd_reg({26'b0,ENTROPY_SRC_ES_ENTROPY_OFFSET},rd_data);
end
repeat (10) @ (posedge clk);
end
//-----------------------------------------------------
if (stress_test) begin
$display("%t Running stress_test...",$time);
thresh_level = 32'h0000_0008;
wr_reg({26'b0,ENTROPY_SRC_INTR_ENABLE_OFFSET},32'h0000_0003); // enable intrs
wr_reg({26'b0,ENTROPY_SRC_ES_SEED_OFFSET},32'h2345_3456); // seed
wr_reg({26'b0,ENTROPY_SRC_ES_RATE_OFFSET},32'h0000_0006); // rate
wr_reg({26'b0,ENTROPY_SRC_ES_THRESH_OFFSET},thresh_level); // thresh level
wr_reg({26'b0,ENTROPY_SRC_ES_CONF_OFFSET},32'h0000_0001); // primary enable
// wait for interrupts to process
while (intrp_cnt < MAX_INTRP_CNT) begin
repeat (20) @ (posedge clk);
end
end
//-----------------------------------------------------
repeat (10) @ (posedge clk);
test_end(errflag);
end
//-------------------------------------
// entropy_src instantiation
//-------------------------------------
entropy_src #(.EsFifoDepth(EsFifoDepth))
u_entropy_src
(
.clk_i(clk),
.rst_ni(rst_n),
.tl_i(tl_i),
.tl_o(tl_o),
.es_entropy_valid_o(es_entropy_valid_o),
.es_entropy_fifo_err_o(es_entropy_fifo_err_o)
);
endmodule