lowRISC / opentitan

OpenTitan: Open source silicon root of trust
https://www.opentitan.org
Apache License 2.0
2.57k stars 770 forks source link

[hw] CSRNG software path without entropy source #5982

Closed moidx closed 3 years ago

moidx commented 3 years ago

I am in the process of writing a functional test case to verify the hw + dif implementation using a known test vector.

https://github.com/lowRISC/opentitan/pull/5973

Test plan based on the test vector requirements:

  1. Enable CSRNG
  2. Instantiate with flag0 = true, and set seed_material to test vector.
  3. Reseed with clen = 0
  4. Generate (1)
  5. Generate (2)
  6. Compare Generate (2) output against expected test vector output.

Currently I can get to step 5 without detecting errors, and I see CSRNG_GENBITS_VLD_GENBITS_VLD_BIT set to 1 before reading from CSRNG_GENBITS_REG, however I am reading all 0's.

Does the CSRNG software path require any additional initialization?

CC: @mwbranstad, @martin-lueker. @tjaychen

Test vectors: https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/random-number-generators

mwbranstad commented 3 years ago

@moidx can you give me the exact values that are written into the sw app command reg? Also, did you intend to do a reseed right after an instantiate (you can, but not sure why)? Need to know the generate commands as well. Also, did you enable AES bypass? can you provide the CTRL write value as well?

tjaychen commented 3 years ago

we can add this test to run in the DV environment also Mark, that might make it easier for you to triage.

On Wed, Apr 7, 2021 at 12:33 PM mwbranstad @.***> wrote:

@moidx https://github.com/moidx can you give me the exact values that are written into the sw app command reg? Also, did you intend to do a reseed right after an instantiate (you can, but not sure why)? Need to know the generate commands as well. Also, did you enable AES bypass? can you provide the CTRL write value as well?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/lowRISC/opentitan/issues/5982#issuecomment-815171354, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2RSS325BHV2Y5WS5P453THSXQHANCNFSM42RJUEFA .

mwbranstad commented 3 years ago

Here is my quick and dirty sequence. AES is turned off, no reseed cmd, just instantiate, then gen1 and gen2. Note the genbits returned are not the same in this case.

  wr_reg({26'b0,CSRNG_CTRL_OFFSET},32'h000000003); // enable block and disable AES block

  $display("%t Request Instantiate cmd on app3...",$time);
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h0000001c1); // instantiate cmd: flag0=1, clen-12
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000001); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000002); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000003); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000004); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000005); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000006); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000007); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000008); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000009); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h00000000a); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h00000000b); // additional data
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h00000000c); // additional data
  wait_for_cmd_ack(0);

  // begin check internal state
  wr_reg({26'b0,CSRNG_HALT_MAIN_SM_OFFSET},32'h000000001);
  cmp_reg({26'b0,CSRNG_MAIN_SM_STS_OFFSET},32'h0000_0001,32'hffff_ffff);

  wr_reg({26'b0,CSRNG_INT_STATE_NUM_OFFSET},32'h000000003);
  cmp_reg({26'b0,CSRNG_INT_STATE_NUM_OFFSET},32'h0000_0003,32'hffff_ffff);
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0001,32'hffff_ffff); // read 0
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0003,32'hffff_ffff); // read 1
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 2
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 3
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 4
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0002,32'hffff_ffff); // read 5
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 6
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 7
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 8
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0001,32'hffff_ffff); // read 9
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 10
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 11
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0000,32'hffff_ffff); // read 12
  cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},32'h0000_0001,32'hffff_ffff); // read 13

  wr_reg({26'b0,CSRNG_HALT_MAIN_SM_OFFSET},32'h000000000);
  cmp_reg({26'b0,CSRNG_MAIN_SM_STS_OFFSET},32'h0000_0000,32'hffff_ffff);
  // end internal state check

  $display("%t Request Generate cmd on app3...",$time);
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h0000_1003); // generate cmd
  wait_for_cmd_ack(0);

  // check genbits through the register i/f
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_0007,32'hffff_ffff);
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_0000,32'hffff_ffff);
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_0000,32'hffff_ffff);
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_0000,32'hffff_ffff);

  $display("%t Request Generate cmd on app3...",$time);
  wait_for_cmd_rdy(0);
  wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h0000_1003); // generate cmd
  wait_for_cmd_ack(0);

  // check genbits through the register i/f
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_000d,32'hffff_ffff);
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_0000,32'hffff_ffff);
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_0000,32'hffff_ffff);
  cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},32'h0000_0000,32'hffff_ffff);
moidx commented 3 years ago

Also, did you intend to do a reseed right after an instantiate (you can, but not sure why)?

This just part of the test vector specification. They expect that order of operations 1. instantiate, 2. reseed, 3. generate, 4. generate.

mwbranstad commented 3 years ago

Reseed with clen = 0

If you do this then, this forces CSRNG to use the ES seed, and will always generate random results between Gen commands.

tjaychen commented 3 years ago

@mwbranstad, i've pushed a commit to #5973 that now allows you to run @moidx test in DV. The first thing it runs into you are already addressing as part of #5983

If you can pull down @moidx PR, you should be able to give it a try in your area. What sorts of problem are you having with top level sims?

moidx commented 3 years ago

Reseed with clen = 0

Is it possible to add support for reseed w/ clen = 0 and flag0 = true? This is something that will come up as part of FIPS known answer tests (I can double check with the lab).

mwbranstad commented 3 years ago

@moidx the csrbg doc does not seem to support this at this time. However, if we use the same definition as the instantiate command, this function could be easy to add.

@tjaychen two problems with full chip. The build step seems to run, but the sim step fails with a message about ninja. Back when this was running ok, we can only run vcs (which is ok but a different tool set), but it cannot produce a wave to debug with - an issue was filed a few weeks ago by @rasmus-madsen

tjaychen commented 3 years ago

hmm...if you're seeing an issue with ninja, then that probably means your software build is not working.

if you go to your repo root, and just do the following, what error do you see?

$ ./meson_init.sh
$ ninja -C build-out all
mwbranstad commented 3 years ago

Unable to find ninja. Please install ninja before running this command. make: *** [sw_build] Error 1

...work/mark.branstad/opentitan>./meson_init.sh Detected $REPO_TOP at /wdc/proj/cto/top/work/mark.branstad/opentitan. Object directory set at /wdc/proj/cto/top/work/mark.branstad/opentitan/build-out. Binary directory set at /wdc/proj/cto/top/work/mark.branstad/opentitan/build-bin. OpenTitan version: opentitan-snapshot-20191101-1-5094-gde7eba3d7

Unable to find ninja. Please install ninja before running this command

tjaychen commented 3 years ago

ah you need to install ninja build The following is just copied from the public install instructions. You can just pick the one you need.

$ sudo apt install autoconf bison build-essential clang-format curl doxygen \ flex g++ git libelf1 libelf-dev libftdi1-2 libftdi1-dev libncurses5 \ libssl-dev libusb-1.0-0 lsb-release make ninja-build pkgconf python3 \ python3-pip python3-setuptools python3-wheel python3-yaml srecord tree \ xsltproc zlib1g-dev xz-utils

On Wed, Apr 7, 2021 at 2:20 PM mwbranstad @.***> wrote:

Unable to find ninja. Please install ninja before running this command. make: *** [sw_build] Error 1

...work/mark.branstad/opentitan>./meson_init.sh Detected $REPO_TOP at /wdc/proj/cto/top/work/mark.branstad/opentitan. Object directory set at /wdc/proj/cto/top/work/mark.branstad/opentitan/build-out. Binary directory set at /wdc/proj/cto/top/work/mark.branstad/opentitan/build-bin. OpenTitan version: opentitan-snapshot-20191101-1-5094-gde7eba3d7

Unable to find ninja. Please install ninja before running this command

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/lowRISC/opentitan/issues/5982#issuecomment-815272724, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2RSRZWNFRCJDLWEXQ4OLTHTEDXANCNFSM42RJUEFA .

mwbranstad commented 3 years ago

@rasmus-madsen or @tunghoang290780 i am assuming we cannot use these directions. Is there process that we use for WD internal?

moidx commented 3 years ago

I am enabling the block with AES enabled. The sequence of commands is as follows:

  1. 0x000001c1 + 12 uint32_t (Instantiate)
  2. 0x00000002 (Reseed)
  3. 0x00004003 (Generate 4 x 128bit)

I have a verilator trace which I can try to share. Some quick observations:

I also pushed some updates to lowrisc/opentitan#5973 to try fix some issues I found in the C code while debugging the waveforms.

rasmus-madsen commented 3 years ago

@mwbranstad we cannot do anything that requires superuser privileges. but we do have ninja 1.10.2 installed image

@tjaychen it looks like the meson_init scripts expects the riscV compiler to be located under /tools/ is this something specific to opentitan? image

rswarbrick commented 3 years ago

For the second point, you can override the toolchain path with TOOLCHAIN_PATH. For example, I've got it set to /src/lr/tools/lowrisc-toolchain-gcc-rv32imc-20200504-1. Set it and then run meson_init.sh and all should be well.

tjaychen commented 3 years ago

@mwbranstad we cannot do anything that requires superuser privileges. but we do have ninja 1.10.2 installed image

@tjaychen it looks like the meson_init scripts expects the riscV compiler to be located under /tools/ is this something specific to opentitan? image

if you look here you can see that there is a default that can also be overwritten by the user.

rasmus-madsen commented 3 years ago

@mwbranstad @tjaychen I will see if I can get this going. but I have some challenges with the symbolic link for cc that points to an old version of cc (4.6) and I do not have permission to change it.

I will keep you posted

martin-lueker commented 3 years ago

For the second point, you can override the toolchain path with TOOLCHAIN_PATH. For example, I've got it set to /src/lr/tools/lowrisc-toolchain-gcc-rv32imc-20200504-1. Set it and then run meson_init.sh and all should be well.

Hi Rupert, This is interesting, though I'm trying to think if there is some way we can leverage this and still use the package manager.

@rasmus-madsen, I'm wondering if there might be a way to just install all the OT system deltas to a group directory, ie. with yum --installroot /our/team/directory/ (Probably a big hog) or rpm --relocate /our/team/directory/ -i <OTRQDPKG_RPMs>. This would be super convenient moving forward. Though I don't know if this would then work with the TOOLCHAIN_PATH trick that Rupert mentioned here.

Any thoughts?

rasmus-madsen commented 3 years ago

@martin-lueker I was thinking a bit along the same lines I am working on resolving some other issues first.

imphil commented 3 years ago

@mwbranstad @rasmus-madsen There are no RPM packages for the RISC-V toolchain (they are binary archives only). The TOOLCHAIN_PATH is about the RISC-V toolchain.

The problem you're seeing is with the host toolchain. For this toolchain you can and should use RPMs provided by RHEL (or maybe your IT department). RHEL provides updated toolchains as part of their SCLs, for example.

I guess the easiest option to figure out the best path forward is a meeting. If you'd like to get help there, please reach out to me or Rupert and we can schedule something.

rswarbrick commented 3 years ago

I agree with what @imphil said. However, since I understand that you guys use module files for your EDA tools, I don't think it would be particularly difficult to wrap up a lowRISC toolchain in a module file (which could then set TOOLCHAIN_PATH for you). I'd guess that your IT department have lots of experience of this sort of thing.

rasmus-madsen commented 3 years ago

I agree with what @imphil said. However, since I understand that you guys use module files for your EDA tools, I don't think it would be particularly difficult to wrap up a lowRISC toolchain in a module file (which could then set TOOLCHAIN_PATH for you). I'd guess that your IT department have lots of experience of this sort of thing.

the problem as I see it is that some of the RPMs that should be installed with the OS are missing. setting the toolchain_path is not a problem - not sure we want to set this with a module as that would make the toolchain shared by all users.

mwbranstad commented 3 years ago

@moidx I looked at the NIST test vectors briefly. This appears very interesting, in that we need to support this and it should confirm the RTL results. I will look into this further.

mwbranstad commented 3 years ago

"I am enabling the block with AES enabled. The sequence of commands is as follows:

0x000001c1 + 12 uint32_t (Instantiate) 0x00000002 (Reseed) 0x00004003 (Generate 4 x 128bit) I have a verilator trace which I can try to share. Some quick observations:

cmd_stage_ack[2:0] seems to toggle at the end of each command. intrs_state.cmd_hw_inst_exec seems to be set early in the boot flow. I haven't looked into it yet. I also pushed some updates to #5973 to try fix some issues I found in the C code while debugging the waveforms."

@moidx I have worked out the sequence that returns 4 x 128b through the sw port. It appears proper to me, but I noticed that the reseed command was requesting for new entropy (entropy_src). If the goal of this test is to be predictable, then the reseed command needs to have seed material also provided.

mwbranstad commented 3 years ago

@moidx with pr #6711 merged now, you should be able to set up the DIF csrng tests and provide input nist test vectors and compare for the no_reseed and pr_false nist output vectors. The pr_true is almost there, but need to figure out the complete solution still, so hold off on those. If you need some sequencing example code, let me know and I can provide.

moidx commented 3 years ago

Hi @mwbranstad, I am revisiting this. Yes, it would be useful if you can share the nist vector sequencing you tried. I can try to add it to the dif level testing. Thanks!

mwbranstad commented 3 years ago

Pasting a snapshot of my system verilog test file. All code is included in this one file to run nist vectors.

// Description: csrng 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 csrng_tb;

  import tlul_pkg::*;
  import entropy_src_pkg::*;
  import aes_pkg::*;
  import csrng_pkg::*;
  import csrng_reg_pkg::*;
  import lc_ctrl_pkg::*;
  import lc_ctrl_state_pkg::*;
  import otp_ctrl_reg_pkg::*;
  import otp_ctrl_pkg::*;
  import otp_ctrl_part_pkg::*;

  // tests
  bit smoke_test = 0;
  bit sen_test = 0;
  bit app1_cmd_test = 0;
  bit ctr_drbg_test = 1;
  bit alert_test = 0;
  bit interrupt_test = 0;

  // options
  bit  msg_rd_data = 0;
  bit  toggle_genbits_rdy = 1;
  int  vector_sel = 1; // 0 = no_reseed, 1 = pr_false, 2 = pr_true

  // parameters`
  localparam NHwApps = 3;
//  localparam INSTID = 2;
  localparam int Cmd = 3;
  localparam int StateId = 4;
  localparam int KeyLen = 256;
  localparam int BlkLen = 128;
  localparam int SeedLen = 384;
  localparam int CtrLen = 32;
//  localparam BE_ARB_N  = 4;
//  localparam BE_ARB_DW  = KEYLEN+BLKLEN;

//  localparam EsFifoDepth = 32;
  localparam MAX_INTRP_CNT = 25;
  localparam WD_DELAY = 1000*MAX_INTRP_CNT;
  localparam [383:0] ENTROPY_INIT = 0;
  localparam [383:0] ENTROPY_INIT_MWB = 384'h0000000C_0000000B_0000000A_00000009_00000008_00000007_00000006_00000005_00000004_00000003_00000002_00000001;
  localparam [383:0] ENTROPY_INIT_SEN = 384'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000_deadbeef;

  // general signals
  logic      clk;
  logic      rst_n;
//  otp_ctrl_part_pkg::otp_hw_cfg_t otp_hw_cfg;

  // tlul signals
  tlul_pkg::tl_h2d_t tl_i;
  tlul_pkg::tl_d2h_t tl_o;

  // entropy signals
  entropy_src_pkg::entropy_src_hw_if_req_t entropy_src_hw_if_o;
  entropy_src_pkg::entropy_src_hw_if_rsp_t entropy_src_hw_if_i;

  // csrng app signals
  csrng_pkg::csrng_req_t  [NHwApps-1:0] csrng_cmd_i;
  csrng_pkg::csrng_rsp_t  [NHwApps-1:0] csrng_cmd_o;

  // lifecycle signals
  lc_ctrl_pkg::lc_tx_t  lc_hw_debug_en_i;

  // imported register parameters (for reference)

  // Register Address

  parameter  int BlockAw = 7;
  parameter logic [BlockAw-1:0] CSRNG_INTR_STATE_OFFSET = 7'h 0;
  parameter logic [BlockAw-1:0] CSRNG_INTR_ENABLE_OFFSET = 7'h 4;
  parameter logic [BlockAw-1:0] CSRNG_INTR_TEST_OFFSET = 7'h 8;
  parameter logic [BlockAw-1:0] CSRNG_ALERT_TEST_OFFSET = 7'h c;
  parameter logic [BlockAw-1:0] CSRNG_REGWEN_OFFSET = 7'h 10;
  parameter logic [BlockAw-1:0] CSRNG_CTRL_OFFSET = 7'h 14;
  parameter logic [BlockAw-1:0] CSRNG_SUM_STS_OFFSET = 7'h 18;
  parameter logic [BlockAw-1:0] CSRNG_CMD_REQ_OFFSET = 7'h 1c;
  parameter logic [BlockAw-1:0] CSRNG_SW_CMD_STS_OFFSET = 7'h 20;
  parameter logic [BlockAw-1:0] CSRNG_GENBITS_VLD_OFFSET = 7'h 24;
  parameter logic [BlockAw-1:0] CSRNG_GENBITS_OFFSET = 7'h 28;
  parameter logic [BlockAw-1:0] CSRNG_HALT_MAIN_SM_OFFSET = 7'h 2c;
  parameter logic [BlockAw-1:0] CSRNG_MAIN_SM_STS_OFFSET = 7'h 30;
  parameter logic [BlockAw-1:0] CSRNG_INT_STATE_NUM_OFFSET = 7'h 34;
  parameter logic [BlockAw-1:0] CSRNG_INT_STATE_VAL_OFFSET = 7'h 38;
  parameter logic [BlockAw-1:0] CSRNG_HW_EXC_STS_OFFSET = 7'h 3c;
  parameter logic [BlockAw-1:0] CSRNG_ERR_CODE_OFFSET = 7'h 40;
  parameter logic [BlockAw-1:0] CSRNG_ERR_CODE_TEST_OFFSET = 7'h 44;

  //---------------------------
  // testbench support
  //---------------------------
  parameter             CNTR_MAX = 200;
  bit                   errflag = 0;
  logic [31:0] rd_data = 0;
  logic [31:0] ctrl_reg = 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;
  logic [31:0] cntr = 0;
  bit          aes_disable;
  logic [1:0]  ins_option;
  logic [383:0] es_seed;
  logic [31:0]  set_cmd;
  logic [383:0] set_adata;
  logic [383:0] adata;
  logic [383:0] entropy_incr = 384'h00000001_00000001_00000001_00000001_00000001_00000001_00000001_00000001_00000001_00000001_00000001_00000001;
  logic [417:0] INTERNAL_STATE1 = 418'h10000000C_0000000B_0000000A_00000008_00000008_00000007_00000006_00000007_00000004_00000003_00000002_00000002_00000001;
  logic [417:0] INTERNAL_STATE2old = 418'h1e000000c_e000000b_e000000a_e0000008_e0000008_e0000007_e0000006_e0000007_e0000004_e0000003_e0000002_e0000002_00000001;
  logic [417:0] INTERNAL_STATE2 = 418'h1e000000d_e000000c_e000000b_e000000b_e0000009_e0000008_e0000007_e0000004_e0000005_e0000004_e0000003_e0000001_00000001;
  logic [417:0] INTERNAL_STATE3 = 418'h1e0000001e0000007e0000001e0000002e0000001e000000fe0000001e0000001e0000001e0000007e0000001e000000000000001;
  logic [127:0] genbits1= 128'h00000000_00000000_00000000_00000007;
  logic [127:0] genbits2= 128'he0000005_e0000004_e0000003_e0000005;

  logic [255:0] initial_key;
  logic [127:0] initial_v;
  logic [31:0]  initial_rc;

  bit           chk_msg;
  logic [31:0]  chk_appnum;
  logic [255:0] chk_key;
  logic [127:0] chk_v;
  logic [31:0]  chk_rc;
  logic [31:0]  chk_sts;
  logic [511:0] chk_bits;

  initial
    begin // force to patch reg errors
      force u_csrng.u_reg.u_chk.err_o = 2'b0;
//      force u_csrng.u_reg.u_reg_if.tl_err = 1'b0;
    end

  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  = TL_A_USER_DEFAULT;
      tl_i.a_mask = 0;
      tl_i.a_data = 0;
      tl_i.d_ready =1;
      entropy_src_hw_if_i.es_ack = 0;
      entropy_src_hw_if_i.es_bits = '0;
      entropy_src_hw_if_i.es_fips = '0;
      for (int i = 0; i < (NHwApps); i++) begin
        csrng_cmd_i[i].csrng_req_valid = 0;
        csrng_cmd_i[i].csrng_req_bus = 0;
        csrng_cmd_i[i].genbits_ready = 1;
      end
      lc_hw_debug_en_i = lc_ctrl_pkg::On;
//      otp_hw_cfg.data.en_csrng_sw_app_read = 8'hA5;
    end

//  bit aes_req;
//  initial // aes pulse
//    begin
//      aes_req = 1'b0;
//      repeat (4) @ (posedge clk);
//      aes_req = 1'b1;
//      repeat (1) @ (posedge clk);
//      aes_req = 1'b0;
//    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;
      entropy_src_hw_if_i.es_bits = es_seed;
      repeat (4) @ (posedge clk);
      if (toggle_genbits_rdy) begin
        forever begin
          repeat (1) @ (posedge clk);
          csrng_cmd_i[1].genbits_ready = 0;
          repeat (6) @ (posedge clk);
          csrng_cmd_i[1].genbits_ready = 1;
        end
      end
    end

  initial // watchdog
    begin
      repeat (WD_DELAY) @ (posedge clk);
      $display("%t %c[1;31mCsrng watchdog triggered -  FAIL!!! %c[0m",$time,27,27);
      $finish;
    end

  task app_req(input int app, logic [383:0] adata, logic [19:0] glen, logic [3:0] flgs, logic [3:0] clen, logic [3:0] acmd);
     repeat (1) @ (posedge clk); #1ps;
     while (csrng_cmd_o[app].csrng_req_ready != 1) begin
       repeat (1) @ (posedge clk); #1ps;
     end
     csrng_cmd_i[app].csrng_req_valid = 1;
     csrng_cmd_i[app].csrng_req_bus = {glen,flgs,clen,acmd};
     repeat (1) @ (posedge clk); #1ps;
     while (csrng_cmd_o[app].csrng_req_ready != 1) begin
       repeat (1) @ (posedge clk); #1ps;
     end
     for (int i=0; i < clen; i=i+1) begin
       if (i==0) begin
         csrng_cmd_i[app].csrng_req_bus = adata[1*32-1:0*32];
       end else if (i==1) begin
         csrng_cmd_i[app].csrng_req_bus = adata[2*32-1:1*32];
       end else if (i==2) begin
         csrng_cmd_i[app].csrng_req_bus = adata[3*32-1:2*32];
       end else if (i==3) begin
         csrng_cmd_i[app].csrng_req_bus = adata[4*32-1:3*32];
       end else if (i==4) begin
         csrng_cmd_i[app].csrng_req_bus = adata[5*32-1:4*32];
       end else if (i==5) begin
         csrng_cmd_i[app].csrng_req_bus = adata[6*32-1:5*32];
       end else if (i==6) begin
         csrng_cmd_i[app].csrng_req_bus = adata[7*32-1:6*32];
       end else if (i==7) begin
         csrng_cmd_i[app].csrng_req_bus = adata[8*32-1:7*32];
       end else if (i==8) begin
         csrng_cmd_i[app].csrng_req_bus = adata[9*32-1:8*32];
       end else if (i==9) begin
         csrng_cmd_i[app].csrng_req_bus = adata[10*32-1:9*32];
       end else if (i==10) begin
         csrng_cmd_i[app].csrng_req_bus = adata[11*32-1:10*32];
       end else if (i==11) begin
         csrng_cmd_i[app].csrng_req_bus = adata[12*32-1:11*32];
       end
       repeat (1) @ (posedge clk); #1ps;
       while (csrng_cmd_o[app].csrng_req_ready != 1) begin
         repeat (1) @ (posedge clk); #1ps;
       end
     end
     csrng_cmd_i[app].csrng_req_valid = 0;
     repeat (1) @ (posedge clk); #1ps;
     while (csrng_cmd_o[app].csrng_req_ready != 1) begin
       repeat (1) @ (posedge clk); #1ps;
     end
  endtask

  //----------------------------
  // NIST routines from 10.2.1
  //----------------------------

  task nist_block_encrypt(input bit aes_off, logic [255:0] key, logic [127:0] v, 
                          output logic [127:0] blkout);
     //repeat (1) @ (posedge clk); #1ps;
     if (aes_off) begin
       blkout = v;
     end else begin
       $display("%t %c[1;31mnist_block_encrypt does not support an AES function -  FAIL!!! %c[0m",$time,27,27);
       $finish;
     end
  endtask

  task nist_update(input bit aes_off, logic [383:0] pdata, logic [255:0] key, logic [127:0] v, 
                   output logic [255:0] keyout, logic [127:0] vout);
     static bit msg = 0;
     localparam SEEDLEN = 384;
     localparam KEYLEN = 256;
     localparam CTR_LEN = 32;
     localparam BLKLEN = 128;
     int temp_len;
     logic [1023:0] temp;
     logic [BLKLEN-1:0] V;
     logic [BLKLEN-1:0] output_block;
     logic [CTR_LEN-1:0] inc;
     // repeat (1) @ (posedge clk); #1ps;

     if (msg) begin
       $display("%t upd pdata: %h",$time,pdata);
       $display("%t upd keyin: %h",$time,key);
       $display("%t upd vin: %h",$time,v);
     end

     V = v;
     temp_len = 0;
     while (temp_len < SEEDLEN) begin
       if (CTR_LEN < BLKLEN) begin
//         inc = (V[CTR_LEN-1:0]+1) % 2**CTR_LEN;   // rightmost - doesn't work as is
         inc = (V[CTR_LEN-1:0]+1);   // rightmost
         V = {(V[BLKLEN-1:BLKLEN-CTR_LEN]),inc}; // leftmost
       end else begin
         V = (V+1) % 2^BLKLEN;
         $display("%t %c[1;31Unexpected path taken in inc loop!! %c[0m",$time,27,27);
       $finish;
       end
       if (msg) begin
         $display("%t upd V: %h",$time,V);
         $display("%t upd inc: %h",$time,V);
       end
       nist_block_encrypt(aes_off,key,V,output_block);
       if (msg) begin
         $display("%t upd output_block: %h",$time,output_block);
       end
       temp = {temp,output_block};
       temp_len = temp_len + BLKLEN;
       if (msg)
         $display("%t upd temp_len: %0d",$time,temp_len);
     end
     if (temp_len !== SEEDLEN) begin
       $display("%t %c[1;31Error in computation of temp_len!! %c[0m",$time,27,27);
       $finish;
     end
       if (msg) begin
         $display("%t upd temp1: %h",$time,temp);
       end
     temp = temp[SEEDLEN-1:0];  // leftmost
       if (msg) begin
         $display("%t upd temp2: %h",$time,temp);
       end
     temp = temp ^ pdata;
     keyout = temp[SEEDLEN-1:SEEDLEN-KEYLEN]; // leftmost
     vout = temp[KEYLEN-1:0];                  // rightmost
     if (msg) begin
       $display("%t upd keyout: %h",$time,keyout);
       $display("%t upd vout: %h",$time,vout);
     end
  endtask

  task nist_instantiate(input bit aes_off, logic [383:0] entropy_input,
                        logic [383:0] personalization_string, logic [7:0] security_strength, 
                        output logic [255:0] keyout, logic [127:0] vout, logic [31:0] reseed_counter);
     static bit msg = 1;
     localparam SEEDLEN = 384;
     localparam KEYLEN = 256;
     localparam CTR_LEN = 32;
     localparam BLKLEN = 128;

     int temp_len;
     logic [383:0] seed_material;
     logic [127:0] v_init;
     logic [127:0] v_temp;
     logic [255:0] key_init;
     logic [255:0] key_temp;

     temp_len = SEEDLEN; // temp = len(personalization_string)
     // if (temp_len < SEEDLEN), then personalization_string = {personalization_string,{SEEDLEN-temp_len{1'b0}};
     if (temp_len !== SEEDLEN) begin
       $display("%t %c[1;31Error in computation of temp_len!! %c[0m",$time,27,27);
       $finish;
     end
     seed_material = entropy_input ^ personalization_string;
     key_init = '0;
     v_init = '0;
     nist_update(aes_off,seed_material,key_init,v_init,key_temp,v_temp);
     keyout = key_temp;
     vout = v_temp;
     reseed_counter = {{CTR_LEN-1{1'b0}},1'b1};
     if (msg) begin
       $display("%t ins keyout: %h",$time,keyout);
       $display("%t ins  vout: %h",$time,vout);
       $display("%t ins    rc: %h",$time,reseed_counter);
     end
  endtask

  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 wait_for_cmd_rdy(input bit debug);
     rd_reg({26'b0,CSRNG_SW_CMD_STS_OFFSET},rd_data); // check the CMD_RDY status bit
     if (debug) $display("%t CSRNG_SW_CMD_STS: rd_data: %h",$time,rd_data);
     while (rd_data[0] != 1) begin
       repeat (1) @ (posedge clk); #1ps;
       rd_reg({26'b0,CSRNG_SW_CMD_STS_OFFSET},rd_data);
       if (debug) $display("%t CSRNG_SW_CMD_STS: rd_data: %h",$time,rd_data);
     end
  endtask

  task wait_for_cmd_ack(input bit debug);
     rd_reg({26'b0,CSRNG_INTR_STATE_OFFSET},rd_data); // check the CMD_ACK status bit
     if (debug) $display("%t CSRNG_INTR_STATE: rd_data: %h",$time,rd_data);
     while (rd_data[0] != 1) begin
       repeat (1) @ (posedge clk); #1ps;
       rd_reg({26'b0,CSRNG_INTR_STATE_OFFSET},rd_data);
       if (debug) $display("%t CSRNG_INTR_STATE: rd_data: %h",$time,rd_data);
     end
     $display("%t Received a command ack...",$time);
     // clear ack status bit
     wr_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0001); // clear the CMD_ACK status bit
     // check ack status bit
     rd_reg({26'b0,CSRNG_INTR_STATE_OFFSET},rd_data); // check the CMD_ACK status bit
     if (debug) $display("%t ,CSRNG_INTR_STATE: rd_data: %h",$time,rd_data);
     if (rd_data[0] === 1'b1) $display("%t ,CSRNG_INTR_STATE: bit 0 is unepectedly set!!! %h",$time,rd_data);
  endtask

  task wait_for_genbits_vld(input bit debug);
     rd_reg({26'b0,CSRNG_GENBITS_VLD_OFFSET},rd_data); // check the CMD_RDY status bit
     if (debug) $display("%t CSRNG_GENBITS_VLD: rd_data: %h",$time,rd_data);
     while (rd_data[0] != 1) begin
       repeat (1) @ (posedge clk); #1ps;
       rd_reg({26'b0,CSRNG_GENBITS_VLD_OFFSET},rd_data);
       if (debug) $display("%t CSRNG_GENBITS_VLD: rd_data: %h",$time,rd_data);
     end
  endtask 

  task send_app_cmd(input bit msg, logic [31:0] appnum, input logic [31:0] acmd, logic [383:0] adata);
     if (1) $display("%t send_app_cmd running on app %0d",$time,appnum);
     if (appnum == 3) begin
       wait_for_cmd_rdy(0);
       wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},acmd); // app cmd
       if ( acmd[7:4] == 12) begin
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[1*32-1:0*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[2*32-1:1*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[3*32-1:2*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[4*32-1:3*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[5*32-1:4*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[6*32-1:5*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[7*32-1:6*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[8*32-1:7*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[9*32-1:8*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[10*32-1:9*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[11*32-1:10*32]); // additional data
         wait_for_cmd_rdy(0);
         wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},adata[12*32-1:11*32]); // additional data
       end
       if ( acmd[3:0] != 3) begin
         wait_for_cmd_ack(0);
       end
     end else if (appnum == 1) begin  
       app_req(appnum,adata,0,1,12,1); // app=app_num,seed,glen=0,flgs=1,clen=12,acmd=1 (instantiate - flag0 on)
       while (csrng_cmd_o[appnum].csrng_rsp_ack != 1) begin
         repeat (1) @ (posedge clk); #1ps;
       end
       $display("%t Ack received for App %0d",$time,appnum);
     end else begin  
       $display("%t %c[1;31msend_app_cmd does not support App %0d %c[0m",$time,appnum,27,27);
       $finish;
     end
  endtask 

  task check_internal_state(input bit msg, logic [31:0] appnum, logic [31:0] sts, logic [255:0] key, logic [127:0] v, logic [31:0] rc);
     static int dump_int_st = 0;
     if (1) $display("%t check_internal_state running on app %0d",$time,appnum);
     // halt main state machine
     wr_reg({26'b0,CSRNG_HALT_MAIN_SM_OFFSET},32'h0000_0001);

     rd_reg({26'b0,CSRNG_MAIN_SM_STS_OFFSET},rd_data); // check the main sm status bit
     if (msg) $display("%t CSRNG_MAIN_SM_STS: rd_data: %h",$time,rd_data);
     while (rd_data[0] != 1) begin
       repeat (1) @ (posedge clk); #1ps;
       rd_reg({26'b0,CSRNG_MAIN_SM_STS_OFFSET},rd_data);
       if (msg) $display("%t CSRNG_MAIN_SM_STS: rd_data: %h",$time,rd_data);
     end
     // verify that main sm is halted
     cmp_reg({26'b0,CSRNG_MAIN_SM_STS_OFFSET},32'h0000_0001,32'hffff_ffff); 
     wr_reg({26'b0,CSRNG_INT_STATE_NUM_OFFSET},appnum);
     cmp_reg({26'b0,CSRNG_INT_STATE_NUM_OFFSET},appnum,32'hffff_ffff);
     if (dump_int_st) begin
       msg_rd_data = 1;
       for (int i=0; i < 14; i=i+1) begin
         $display("%t word %0d ",$time,i);
         rd_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},rd_data);
       end
       msg_rd_data = 0;
     end else begin
       if (msg) $display("%t rc word0 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},rc,32'hffff_ffff); // reseed cntr [31:0]
       if (msg) $display("%t v word0 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},v[1*32-1:0*32],32'hffff_ffff); // V
       if (msg) $display("%t v word1 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},v[2*32-1:1*32],32'hffff_ffff); // read 2
       if (msg) $display("%t v word2 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},v[3*32-1:2*32],32'hffff_ffff); // read 3
        if (msg) $display("%t v word3 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},v[4*32-1:3*32],32'hffff_ffff); // read 4
       if (msg) $display("%t key word0 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[1*32-1:0*32],32'hffff_ffff); // read 5
       if (msg) $display("%t key word1 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[2*32-1:1*32],32'hffff_ffff); // read 6
       if (msg) $display("%t key word2 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[3*32-1:2*32],32'hffff_ffff); // read 7
       if (msg) $display("%t key word3 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[4*32-1:3*32],32'hffff_ffff); // read 8
       if (msg) $display("%t key word4 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[5*32-1:4*32],32'hffff_ffff); // read 9
       if (msg) $display("%t key word5 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[6*32-1:5*32],32'hffff_ffff); // read 10
       if (msg) $display("%t key word6 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[7*32-1:6*32],32'hffff_ffff); // read 11
       if (msg) $display("%t key word7 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},key[8*32-1:7*32],32'hffff_ffff); // read 12
       if (msg) $display("%t status word0 ",$time);
       cmp_reg({26'b0,CSRNG_INT_STATE_VAL_OFFSET},sts,32'hffff_ffff); // read 13
     end 

     wr_reg({26'b0,CSRNG_HALT_MAIN_SM_OFFSET},32'h000000000);
     cmp_reg({26'b0,CSRNG_MAIN_SM_STS_OFFSET},32'h0000_0000,32'hffff_ffff);
  endtask

  task check_genbits(input bit msg, logic [31:0] appnum, logic [127:0] genbits);
     if (msg) $display("%t check_genbits running on app %0d",$time,appnum);
     if (genbits != '0) begin
       wait_for_genbits_vld(0);
       cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[1*32-1:0*32],32'hffff_ffff);
       cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[2*32-1:1*32],32'hffff_ffff);
       cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[3*32-1:2*32],32'hffff_ffff);
       cmp_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[4*32-1:3*32],32'hffff_ffff);
     end else begin
       wait_for_genbits_vld(0);
       rd_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[1*32-1:0*32]);
       rd_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[2*32-1:1*32]);
       rd_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[3*32-1:2*32]);
       rd_reg({26'b0,CSRNG_GENBITS_OFFSET},genbits[4*32-1:3*32]);
     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;31mCsrng Test FAIL!!! %c[0m",$time,27,27);
     end else begin
       $display("%t %c[1;32mCsrng Test PASSED... %c[0m",$time,27,27);
     end
     $finish;
  endtask

  always @ (posedge entropy_src_hw_if_o.es_req)
    begin
      if (rst_n) begin  // handle reset case
        if (entropy_src_hw_if_o.es_req) begin
          repeat (1) @ (posedge clk); #1ps;
          entropy_src_hw_if_i.es_ack = 1'b1;
//          entropy_cntr=entropy_cntr+entropy_incr;
//          entropy_src_hw_if_i.es_bits = entropy_cntr;
          entropy_src_hw_if_i.es_bits = es_seed;
          repeat (1) @ (posedge clk); #1ps;
          entropy_src_hw_if_i.es_ack = 1'b0;
        end else begin
          #1ps;
        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);
      // CONFIGURE
      cmp_reg({26'b0,CSRNG_CTRL_OFFSET},32'h0000_0000,32'hffff_ffff);
      wr_reg({26'b0,CSRNG_CTRL_OFFSET},32'h000000003);
      cmp_reg({26'b0,CSRNG_CTRL_OFFSET},32'h0000_0003,32'hffff_ffff);

      // INSTANTIATE
      chk_msg = 0;
      chk_appnum = 3;
      chk_sts = 1;
      chk_key = 256'h0000000000000000000000000000000100000000000000000000000000000002;
      chk_v   = 128'h00000000000000000000000000000003;
      chk_rc  = 32'h0000_0001;

      wait_for_cmd_rdy(0);
      $display("%t Request Instantiate cmd on SW App3...",$time);
      wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h000000101); // instantiate cmd
      wait_for_cmd_ack(0);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

      // GENERATE
      chk_msg = 0;
      chk_appnum = 3;
      chk_sts = 1;
      chk_key = 256'h0000000000000000000000000000000500000000000000000000000000000006;
      chk_v   = 128'h00000000000000000000000000000007;
      chk_rc  = 32'h0000_0002;
      chk_bits = 512'h00000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
      wait_for_cmd_rdy(0);
      $display("%t Request Generate cmd on SW app3...",$time);
      wr_reg({26'b0,CSRNG_CMD_REQ_OFFSET},32'h0000_1003); // generate cmd

      wait_for_genbits_vld(0);
      check_genbits(chk_msg,chk_appnum,chk_bits[512-1:384]);
      wait_for_cmd_ack(0);

      // final check: check the internal state
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

    end else if (app1_cmd_test) begin
      $display("%t Running app1_cmd_test...",$time);
      wr_reg({26'b0,CSRNG_CTRL_OFFSET},32'h000000001); // enable

      // INSTANTIATE -------------------------------------------------------------------------
      set_cmd = 32'h000001c1;
      set_adata = 384'hdf5d73faa468649edda33b5cca79b0b05600419ccb7a879ddfec9db32ee494e5531b51de16a30f769262474c73bec010;
      chk_msg = 0;
      chk_appnum = 1;
      chk_sts = 1;
      chk_key = 256'h8c52f901632d522774c08fad0eb2c33b98a701a1861aecf3d8a25860941709fd;
      chk_v = 128'h217b52142105250243c0b2c206b8f59e;
      chk_rc = 32'h0000_0001;

      $display("%t Request Instantiate cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

//      app_req(chk_appnum,0,1,12,1); // app=app_num,glen=0,flgs=1,clen=12,acmd=1 (instantiate - flag0 on)
//      while (csrng_cmd_o[app_num].csrng_rsp_ack != 1) begin
//        repeat (1) @ (posedge clk); #1ps;
//      end
//      $display("%t Ack received for App %0d",$time,app_num);

//      repeat (20) @ (posedge clk); #1ps;
//      app_req(app_num,4,0,0,3); // app=app_num,glen=4,flgs=0,clen=0,acmd=3 (generate - flag0 off)
//      while (csrng_cmd_o[app_num].genbits_valid != 1) begin
//        repeat (1) @ (posedge clk); #1ps;
//      end
//      $display("%t Genbits received for App %0d",$time,app_num);
//      if (csrng_cmd_o[app_num].genbits_bus !== genbits1) begin
//        $display("%t   Actual: %h",$time,csrng_cmd_o[app_num].genbits_bus);
//        $display("%t Expected: %h",$time,genbits1);
//        $display("%t Error in genbits cmd...",$time); errflag = 1;
//      end
//
//      repeat (200) @ (posedge clk); #1ps;

    end else if (sen_test) begin
      $display("%t Running sen_test...",$time);
      wr_reg({26'b0,CSRNG_CTRL_OFFSET},32'h000000001); // enable

      // INSTANTIATE -------------------------------------------------------------------------
      set_cmd = 32'h000001c1;
      set_adata = 384'h0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadbeef;
      chk_msg = 0;
      chk_appnum = 1;
      chk_sts = 32'h00000001;
      chk_key = 256'h530f8afb_c74536b9_a963b4f1_c4cb738b_cea7403d_4d606b6e_074ec5d3_baf39d18;
      chk_v = 128'h726003ca_37a62a74_d1a2f58e_abab8b61;
      chk_rc = 32'h0000_0001;

      $display("%t Request Instantiate cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

    end else if (ctr_drbg_test) begin
      $display("%t Running ctr_drbg...",$time);
      if (vector_sel == 2) begin
        $display("%t  Using pr_true vectors...",$time);
      end else if (vector_sel == 1) begin
        $display("%t  Using pr_false vectors...",$time);
      end else begin
        $display("%t  Using no_reseed vectors...",$time);
      end      

      wr_reg({26'b0,CSRNG_CTRL_OFFSET},32'h00000001); // enable block

      // INSTANTIATE -------------------------------------------------------------------------
      set_cmd = 32'h000001c1;
      chk_msg = 0;
      chk_appnum = 3;
      if (vector_sel == 2) begin
        // pr_true
        set_adata = 384'hfaf346c9c8afbc5ab6e33ce492247fac6db9a7ba4297557f587a42563ddf56c90e41c6afb56233815b74e091bac7d8e5;
        chk_sts   =  32'h0000_0001;
        chk_key   = 256'ha9fccc320fea8ae31f80881556ef0c27a31ee7870ff73e115f348785872ccbd1;
        chk_v     = 128'h7c21c56582c419f58ad6151fcfc1ed6b;
        chk_rc    =  32'h0000_0001;
      end else if (vector_sel == 1) begin
        // pr_false
        set_adata = 384'he4bc23c5089a19d86f4119cb3fa08c0a4991e0a1def17e101e4c14d9c323460a7c2fb58e0b086c6c57b55f56cae25bad;
        chk_sts   =  32'h0000_0001;
        chk_key   = 256'hb7b3a93ecfdf2f61c622ad3afb6bff818736a09c9391157e1902d10a79d0db12;
        chk_v     = 128'h0e4fb6443cae46188617aad8bfe46e23;
        chk_rc    =  32'h0000_0001;
      end else begin
        // no_reseed
        set_adata = 384'hdf5d73faa468649edda33b5cca79b0b05600419ccb7a879ddfec9db32ee494e5531b51de16a30f769262474c73bec010;
        chk_sts   =  32'h0000_0001;
        chk_key   = 256'h8c52f901632d522774c08fad0eb2c33b98a701a1861aecf3d8a25860941709fd;
        chk_v     = 128'h217b52142105250243c0b2c206b8f59e;
        chk_rc    =  32'h0000_0001;
      end

      $display("%t Request Instantiate 1 cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

      // RESEED -------------------------------------------------------------------------
      if (vector_sel != 0) begin
        set_cmd = 32'h000001c2;
        chk_msg = 0;
        chk_appnum = 3;
        if (vector_sel == 2) begin
          // pr_false
          set_adata = 384'hdfc111252d7146922713720ae1e348a07ae403b5238fefb4e8592f6f6cc4a61c94828db84c6faecd1502261008011f2c;
          chk_sts   =  32'h0;
          chk_key   = 256'h0;
          chk_v     = 128'h0;
          chk_rc    =  32'h0;
        end else if (vector_sel == 1) begin
          // pr_false
          set_adata = 384'hfd85a836bba85019881e8c6bad23c9061adc75477659acaea8e4a01dfe07a1832dad1c136f59d70f8653a5dc118663d6;
          chk_sts   =  32'h0000_0001;
          chk_key   = 256'hd230044c2594510d195ffe9923de8848bdbd19f24d0e7558b28e55b2d4de7841;
          chk_v     = 128'he18637ff12f514f37adc2013a40f38c1;
          chk_rc    =  32'h0000_0001;
        end else begin
          // no_reseed
          set_adata = '0;
          chk_sts   = '0;
          chk_key   = '0;
          chk_v     = '0;
          chk_rc    = '0;
        end

        $display("%t Request Reseed 1 cmd on app3...",$time);
        send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
        if (vector_sel == 1) begin
          check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);
        end
      end

      // GENERATE 1 ----------------------------------------------------------------------------
      set_cmd = 32'h0000_4003;
      chk_msg = 0;
      chk_appnum = 3;
      if (vector_sel == 2) begin
        chk_bits = 512'h0;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'h59ab2aa229c17b2ccf5b633ad905aa4396d717cd7109c4396176b445e23b54b0;
        chk_v    = 128'h9ac50e38805dab58baf6429436e00b39;
        chk_rc   =  32'h0000_0002;
      end else if (vector_sel == 1) begin
        chk_bits = 512'h0;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'hec871bb7a4f2c45dccdd0e514a21628959aa21e9643934f619b2709b3e38697c;
        chk_v    = 128'hd8bbe7bfc60bfb710f39acd1088c9f41;
        chk_rc   =  32'h0000_0002;
      end else begin
        chk_bits = 512'h0b16530817166e90cf763d08378fca1ec01a083914117211a69b1bf1359fbe3e6e48e546ce7ab38fc5e00eb858d7e45d5d6e1012c58a553e88a65ec749de93f9;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'h72f4af5c93258eb3eeec8c0cacea6c1d1978a4fad44312725f1ac43b167f2d52;
        chk_v    = 128'he86f6d07dfb551cebad80e6bf6830ac4;
        chk_rc   =  32'h0000_0002;
      end

     $display("%t Request Generate 1 cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);

      // check genbits through the register i/f
      check_genbits(chk_msg,chk_appnum,chk_bits[512-1:384]);
      check_genbits(chk_msg,chk_appnum,chk_bits[384-1:256]);
      check_genbits(chk_msg,chk_appnum,chk_bits[256-1:128]);
      check_genbits(chk_msg,chk_appnum,chk_bits[128-1:0]);

      // final command wait
      wait_for_cmd_ack(0);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

      // RESEED PR 1 -------------------------------------------------------------------------
      if (vector_sel == 2) begin
        set_cmd = 32'h000001c2;
        chk_msg = 0;
        chk_appnum = 3;
        if (vector_sel == 2) begin
          // pr_false
          set_adata = 384'hd4528bac5b99c772347d44f4ece79bc811ca8ebea9483fa5f5040c02f77069dad1aec7adaa8a9a6a9ddabab045d328a90;
          chk_sts   =  32'h0;
          chk_key   = 256'h0;
          chk_v     = 128'h0;
          chk_rc    =  32'h0;
        end else if (vector_sel == 1) begin
          // pr_false
          set_adata = '0;
          chk_sts   = '0;
          chk_key   = '0;
          chk_v     = '0;
          chk_rc    = '0;
        end else begin
          // no_reseed
          set_adata = '0;
          chk_sts   = '0;
          chk_key   = '0;
          chk_v     = '0;
          chk_rc    = '0;
        end

        $display("%t Request Reseed PR 1 cmd on app3...",$time);
        send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
      end

      // GENERATE 2 ----------------------------------------------------------------------------
      set_cmd = 32'h0000_4003;
      chk_msg = 0;
      chk_appnum = 3;
      if (vector_sel == 2) begin
        chk_bits = 512'hbc013dc891db12c34ad11944805bf13dfd67ff2c23176d83f5b396b69e400042252e11816c3095421137181a5d0ee37c83a339c58d080946ca90aa437d50d9cf;
        chk_sts  = 32'h0000_0001;
        chk_key  = 256'h48f4632bbc79c4bde48a8588a5395afcdccc84f2a3b25b8be2715cd8f9dd8a6b;
        chk_v    = 128'h24f485205e3baf899b8c226c2ffc73ce;
        chk_rc   = 32'h0000_0003;
//        chk_rc   = 32'h0000_0002; // TODO: fix bug here
      end else if (vector_sel == 1) begin
        chk_bits = 512'hb2cb8905c05e5950ca31895096be29ea3d5a3b82b269495554eb80fe07de43e193b9e7c3ece73b80e062b1c1f68202fbb1c52a040ea2478864295282234aaada;
        chk_sts  = 32'h0000_0001;
        chk_key  = 256'he728308a0e92cbacb269d12246d8e2d24cf5fcc678aa09564132e4972c456eda;
        chk_v    = 128'hc95f38da34ecb65ebf8b34c32bc215a5;
        chk_rc   = 32'h0000_0003;
      end else begin
        chk_bits = 512'hd1c07cd95af8a7f11012c84ce48bb8cb87189e99d40fccb1771c619bdf82ab2280b1dc2f2581f39164f7ac0c510494b3a43c41b7db17514c87b107ae793e01c5;
        chk_sts  = 32'h0000_0001;
        chk_key  = 256'h1a1c6e5f1cccc6974436e5fd3f015bc8e9dc0f90053b73e3c19d4dfd66d1b85a;
        chk_v    = 128'h53c78ac61a0bac9d7d2e92b1e73e3392;
        chk_rc   = 32'h0000_0003;
      end

     $display("%t Request Generate 2 cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);

      // check genbits through the register i/f
      check_genbits(chk_msg,chk_appnum,chk_bits[512-1:384]);
      check_genbits(chk_msg,chk_appnum,chk_bits[384-1:256]);
      check_genbits(chk_msg,chk_appnum,chk_bits[256-1:128]);
      check_genbits(chk_msg,chk_appnum,chk_bits[128-1:0]);

      // final command wait
      wait_for_cmd_ack(0);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

      // UNINSTANTIATE -------------------------------------------------------------------------
      set_cmd = 32'h0000_0005;
      chk_msg = 0;
      chk_appnum = 3;
      chk_rc   = 32'h0000_0000;
      chk_key  = 256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
      chk_v    = 128'h00000000_00000000_00000000_00000000;
      chk_sts   = 32'h0000_0000;

      $display("%t Request uninstantiate cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

      if (vector_sel == 4) begin
        $display("%t Debug stop...",$time);
        $finish;
      end

      // INSTANTIATE -------------------------------------------------------------------------
      set_cmd = 32'h000001c1;
      chk_msg = 0;
      chk_appnum = 3;
      if (vector_sel == 2) begin
        set_adata = 384'he5d15d661cc3a5a7fb15f940554461a7c1b886a9c939d632d36d3e785c713ea2dff944485b9b35bd7503245b2081f82d;
        chk_sts = 32'h0000_0001;
        chk_key = 256'hb6ded79ddb86931e52764db1918f122c0f1fc6948459bd5cd423fbabe682a3ba;
        chk_v = 128'had9947826c3d1fc9a4a1d1d55587cda3;
        chk_rc = 32'h0000_0001;
      end else if (vector_sel == 1) begin
        set_adata = 384'hedfdb55e77d418a63e4414dfd42225ed257cf74e99325fba26e8f3a4524a71bc80a731af23256908cb4675a9c253ea6f;
        chk_sts = 32'h0000_0001;
        chk_key = 256'hbef23fa5b0912e1f9727a02e10e95666ebdbb773d45234d421a63677e8b9eca4;
        chk_v = 128'hf2c732651483437c1ae48027b755dfe1;
        chk_rc = 32'h0000_0001;
      end else begin
        set_adata = 384'h3b6fb634d35bb386927374f991c1cbc9fafba3a43c432dc411b7b2fa96cfcce8d305e135ff9bc460dbc7ba3990bf8060;
        chk_sts = 32'h0000_0001;
        chk_key = 256'h68603ccf141e853f3b10c008550ab842345ce399712346aa16f977292c3c51f0;
        chk_v = 128'ha165e2ffc83dee140a654fb7e5b9b5ee;
        chk_rc = 32'h0000_0001;
      end

      $display("%t Request Instantiate 2 cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

      // RESEED -------------------------------------------------------------------------
      if (vector_sel != 0) begin
        set_cmd = 32'h000001c2;
        chk_msg = 0;
        chk_appnum = 3;
        if (vector_sel == 2) begin
          // pr_false
          set_adata = 384'h0b2c49e216ef47df86254867b61969ac631c4b6a68f644cb2a6b89c7f6282faf403dccd9177b90aba32535fccea488e9;
          chk_sts   =  32'h0;
          chk_key   = 256'h0;
          chk_v     = 128'h0;
          chk_rc    =  32'h0;
        end else if (vector_sel == 1) begin
          // pr_false
          set_adata = 384'ha9372fea93d607fbbc75a97b7f65f2d4ae8c06bd184981572e888a35c5794d2bb380a4ae04bba27f2efcc9e7914b96dc;
          chk_sts   =  32'h0000_0001;
          chk_key   = 256'hfa8718f94465637aafba7e3ae46724b1a7273a7af78c54745e6cf22cb4238bf2;
          chk_v     = 128'h47fb218a3c1d31b7a7e01e829666cddd;
          chk_rc    =  32'h0000_0001;
        end else begin
          // no_reseed
          set_adata = '0;
          chk_sts   = '0;
          chk_key   = '0;
          chk_v     = '0;
          chk_rc    = '0;
        end

        $display("%t Request Reseed 1 cmd on app3...",$time);
        send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
        if (vector_sel == 1) begin
          check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);
        end
      end

      // GENERATE 3 ----------------------------------------------------------------------------
      set_cmd = 32'h0000_4003;
      chk_msg = 0;
      chk_appnum = 3;
      if (vector_sel == 2) begin
        chk_bits = 512'h0;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'h4446242d27df8496599e18a414956a0de73f037d68166c1c99cf31ba40893531;
        chk_v    = 128'h044a309cb8f887d3293b25d25e67dd19;
        chk_rc   =  32'h0000_0002;
      end else if (vector_sel == 1) begin
        chk_bits = 512'h0;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'haf3a71c889964fa84a4209646702cff0a4c61d10e4d6eb288f67842f026bff75;
        chk_v    = 128'h6f2e3ab7a6e8697cdcf4060896e66c0f;
        chk_rc   =  32'h0000_0002;
      end else begin
        chk_bits = 512'hcc69107953b23610bde171fcd81092a0402b2bffa6d39aba0548ae97d85a4bb7af011898fd97dfe0dc264a2eb0792e212b626c66ae97d59895096d59a62cd2a8;
        chk_sts   = 32'h0000_0001;
        chk_key  = 256'hf3ae40b109548d29a30a56c848a2ee97c09706efdd2760fcd85c1f6b0386ec9;
        chk_v    = 128'h85cbbdd3d168a48fdf485b5ee8fec428;
        chk_rc   = 32'h0000_0002;
      end

     $display("%t Request Generate 3 cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);

      // check genbits through the register i/f
      check_genbits(chk_msg,chk_appnum,chk_bits[512-1:384]);
      check_genbits(chk_msg,chk_appnum,chk_bits[384-1:256]);
      check_genbits(chk_msg,chk_appnum,chk_bits[256-1:128]);
      check_genbits(chk_msg,chk_appnum,chk_bits[128-1:0]);

      // final command wait
      wait_for_cmd_ack(0);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

      // RESEED PR 2 -------------------------------------------------------------------------
      if (vector_sel == 2) begin
        set_cmd = 32'h000001c2;
        chk_msg = 0;
        chk_appnum = 3;
        if (vector_sel == 2) begin
          // pr_false
          set_adata = 384'hc6c46e98fa4b87d5e398df48aada1a713c2f7bceb366a1a746daff600618835f57475379631daad46ef01c78f4ed2154;
          chk_sts   =  32'h0;
          chk_key   = 256'h0;
          chk_v     = 128'h0;
          chk_rc    =  32'h0;
        end else if (vector_sel == 1) begin
          // pr_false
          set_adata = '0;
          chk_sts   = '0;
          chk_key   = '0;
          chk_v     = '0;
          chk_rc    = '0;
        end else begin
          // no_reseed
          set_adata = '0;
          chk_sts   = '0;
          chk_key   = '0;
          chk_v     = '0;
          chk_rc    = '0;
        end

        $display("%t Request Reseed PR 2 cmd on app3...",$time);
        send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);
      end

      // GENERATE 4 ----------------------------------------------------------------------------
      set_cmd = 32'h0000_4003;
      chk_msg = 0;
      chk_appnum = 3;
      if (vector_sel == 2) begin
        chk_bits = 512'h4963a8a8442d8d03ed868f027021c669d3a07980e56fe5ef6100413b9a1c23072977324f2d80bc4d1e2595400d4901f20e4bf17f960055dc1ff346c423807010;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'h3d845aa67b16eb390f8a6b8bda0998a7106dac0f40ed4e89fa6ce835423ecc57;
        chk_v    = 128'h1779a85b3222d0510bb0e30f09f8af0e;
        chk_rc   =  32'h0000_0003;
//        chk_rc   = 32'h0000_0002; // TODO: fix bug here
      end else if (vector_sel == 1) begin
        chk_bits = 512'h11b1a0f0bb935ec0c54e089e0cd20832d1f00e7069f30e9ea2e35b7f15ecf0577d0e90035bf0f91ffd9e8a1fa8a507503739afbec19393e02c9b7c230cdea36f;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'h6d3e50247b7197bd25978339272004e3bd7d854e277cc8390f3f2081a2584c2d;
        chk_v    = 128'h85f63f7d2dcb861010e525ffdd221cb3;
        chk_rc   =  32'h0000_0003;
      end else begin
        chk_bits = 512'h83a836fe1cde053164555529409337dc4fec6844594fdf15083ba9d1001eb945c3b96a1bcee3990e1e51f85c80e9f4e04de34e57b640f6cae8ed68e99624712;
        chk_sts  =  32'h0000_0001;
        chk_key  = 256'hfb63a736069acd25a9ba49865d167e8c506e787c999e5509faa75129c2c26625;
        chk_v    = 128'h3bccc6785beb8d11ace6816d0378ad1e;
        chk_rc   =  32'h0000_0003;
      end

     $display("%t Request Generate 4 cmd on app3...",$time);
      send_app_cmd(chk_msg,chk_appnum,set_cmd,set_adata);

      // check genbits through the register i/f
      check_genbits(chk_msg,chk_appnum,chk_bits[512-1:384]);
      check_genbits(chk_msg,chk_appnum,chk_bits[384-1:256]);
      check_genbits(chk_msg,chk_appnum,chk_bits[256-1:128]);
      check_genbits(chk_msg,chk_appnum,chk_bits[128-1:0]);

      // final command wait
      wait_for_cmd_ack(0);
      check_internal_state(chk_msg,chk_appnum,chk_sts,chk_key,chk_v,chk_rc);

    end else if (alert_test) begin
      $display("%t Running alert_test...",$time);
      wr_reg({26'b0,CSRNG_CTRL_OFFSET},32'h000000003); // disable AES
      for (int i = 0; i < 16; i++) begin
        $display("%t Setting bit %0d",$time,i);
        wr_reg({26'b0,CSRNG_ERR_CODE_TEST_OFFSET},i); // set a fatal error
        $display("%t Check if set %0d",$time,i);
        cmp_reg({26'b0,CSRNG_ERR_CODE_OFFSET},(1 << i),(1 << i));
        cmp_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0008,32'hffff_ffff);
        // clear err_code reg
        $display("%t Clear interrupt status reg",$time);
        wr_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0008); // clear reg
        cmp_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0000,32'hffff_ffff);
      end
      for (int i = 20; i < 26; i++) begin
        $display("%t Setting bit %0d",$time,i);
        wr_reg({26'b0,CSRNG_ERR_CODE_TEST_OFFSET},i); // set a fatal error
        $display("%t Check if set %0d",$time,i);
        cmp_reg({26'b0,CSRNG_ERR_CODE_OFFSET},(1 << i),(1 << i));
        cmp_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0008,32'hffff_ffff);
        // clear err_code reg
        $display("%t Clear interrupt status reg",$time);
        wr_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0008); // clear reg
        cmp_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0000,32'hffff_ffff);
      end
      for (int i = 28; i < 31; i++) begin
        $display("%t Setting bit %0d",$time,i);
        wr_reg({26'b0,CSRNG_ERR_CODE_TEST_OFFSET},i); // set a fatal error
        $display("%t Check if set %0d",$time,i);
        cmp_reg({26'b0,CSRNG_ERR_CODE_OFFSET},(1 << i),(1 << i));
        cmp_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0008,32'hffff_ffff);
        // clear err_code reg
        $display("%t Clear interrupt status reg",$time);
        wr_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0008); // clear reg
        cmp_reg({26'b0,CSRNG_INTR_STATE_OFFSET},32'h0000_0000,32'hffff_ffff);
      end
    end else begin // initial begin
      $display("%t No test selected...",$time);
    end
    //-----------------------------------------------------
    repeat (10) @ (posedge clk);
    test_end(errflag);
  end

  //-------------------------------------
  // csrng instantiation
  //-------------------------------------

  csrng
    #(.NHwApps(NHwApps))
      u_csrng
        (
         .clk_i(clk),
         .rst_ni(rst_n),
         .tl_i(tl_i),
         .tl_o(tl_o),

         .otp_en_csrng_sw_app_read_i(otp_ctrl_pkg::Enabled),

         .lc_hw_debug_en_i(lc_hw_debug_en_i),
         // Entropy Interface
         .entropy_src_hw_if_o(entropy_src_hw_if_o),
         .entropy_src_hw_if_i(entropy_src_hw_if_i),

         // Entropy Interface
         .cs_aes_halt_i(1'b0),
         .cs_aes_halt_o(),

         // Application Interfaces
         .csrng_cmd_i(csrng_cmd_i),
         .csrng_cmd_o(csrng_cmd_o),

         .alert_tx_o(),
         .alert_rx_i(4'h0),

         .intr_cs_cmd_req_done_o(),
         .intr_cs_entropy_req_o(),
         .intr_cs_hw_inst_exc_o(),
         .intr_cs_fatal_err_o()
         );

//  //-------------------------------------
//  // aes quick test
//  //-------------------------------------
//  parameter aes_pkg::sbox_impl_e SBoxImpl = aes_pkg::SBoxImplLut;
//
//  csrng_block_encrypt #(
//    .SBoxImpl(SBoxImpl),
//    .Cmd(Cmd),
//    .StateId(StateId),
//    .BlkLen(BlkLen),
//    .KeyLen(KeyLen)
//  ) u_csrng_block_encrypt (
//    .clk_i(clk),
//    .rst_ni(rst_n),
//    .block_encrypt_bypass_i(1'b0),
//    .block_encrypt_enable_i(1'b1),
//    .block_encrypt_lc_hw_debug_not_on_i(1'b1),
//    .block_encrypt_req_i(aes_req),
//    .block_encrypt_rdy_o(),
////    .block_encrypt_key_i(256'h8c52f901632d522774c08fad0eb2c33b98a701a1861aecf3d8a25860941709fd),
////    .block_encrypt_v_i(128'h217b52142105250243c0b2c206b8f59f),
//    .block_encrypt_key_i(256'h000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f),
//    .block_encrypt_v_i(128'h00112233445566778899aabbccddeeff),
//    .block_encrypt_cmd_i(3'h6),
//    .block_encrypt_id_i(4'h3),
//    .block_encrypt_ack_o(),
//    .block_encrypt_rdy_i(1'b1),
//    .block_encrypt_cmd_o(),
//    .block_encrypt_id_o(),
//    .block_encrypt_v_o(),
//    .block_encrypt_quiet_o(),
//    .block_encrypt_aes_cipher_sm_err_o(),
//    .block_encrypt_sfifo_blkenc_err_o()
//  );

endmodule
moidx commented 3 years ago

Thanks @mwbranstad, I am trying the following vector, which is used in the tb from your previous comment:

COUNT = 0
EntropyInput = df5d73faa468649edda33b5cca79b0b05600419ccb7a879ddfec9db32ee494e5531b51de16a30f769262474c73bec010
Nonce = 
PersonalizationString = 
** INSTANTIATE:
    Key = 8c52f901632d522774c08fad0eb2c33b98a701a1861aecf3d8a25860941709fd
    V   = 217b52142105250243c0b2c206b8f59e

I am using flag0 = 1 in order to skip mixing the entropy source, however, the update command seems to be mixing the seed coming from the entropy source.

flag0

It seems that this is happening because in csrng_core.sv

  assign cmd_entropy_avail = entropy_src_hw_if_i.es_ack;
  // Capture entropy from entropy_src
  assign entropy_src_seed_d =
         (cmd_entropy_avail && flag0_q) ? '0 : // special case where zero is used
         cmd_entropy_avail ? (entropy_src_hw_if_i.es_bits ^ seed_diversification) :
         entropy_src_seed_q;
  assign entropy_src_fips_d =
         (cmd_entropy_avail && flag0_q) ? '0 : // special case where zero is used
         cmd_entropy_avail ? entropy_src_hw_if_i.es_fips :
         entropy_src_fips_q;

When flag0_q = 1, isn't that sufficient to set the entropy_src_seed to '0?

mwbranstad commented 3 years ago

just for clarity, the "update" command should not be used for the nist vectors test, as that is a private one - maybe you just meant "instantiate" command. For the scenario, your instantiate command should be -> 32'h0000_01c1 (flag0 set, clen=12, instantiate cmd) Then set the "adata" to the seed value (EntropyInput). Once done, the internal state should have the above key, v, and rc values updated.

I can look at a wave if need be.

moidx commented 3 years ago

Hi @mwbranstad, that is correct, I am looking at the instantiate command with flag0 set (32'h0000_01c1). In order to implement the KAT test for the DRBG.instantiate function, I need to access to the internal state values k and v. Right now CSRNG is mixing the entropy_src with adata even if flag0 = 1'b1, which causes the KAT test to fail.

I ended up looking at the internal update function to try to debug why the output was different from the expected k, v values and found that even if flag0 = 1'b1, entropy_seed was still getting mixed with adata because entropy_src_hw_if_i.es_ack = false. Since the KAT test is purely driven by sw, I added the question in the comment above to check if it is possible to modify the entropy_src_seed assignment in csrng_core.sv to something like this:

 assign cmd_entropy_avail = entropy_src_hw_if_i.es_ack;
  // Capture entropy from entropy_src
  assign entropy_src_seed_d =
         flag0_q ? '0 : // special case where zero is used
         cmd_entropy_avail ? (entropy_src_hw_if_i.es_bits ^ seed_diversification) :
         entropy_src_seed_q;
  assign entropy_src_fips_d =
         flag0_q ? '0 : // special case where zero is used
         cmd_entropy_avail ? entropy_src_hw_if_i.es_fips :
         entropy_src_fips_q;

The above changes are sufficient to get the KAT test to pass, but I am not sure if there are any additional changes required.

moidx commented 3 years ago

lowrisc/opentitan#7309

moidx commented 3 years ago

lowrisc/opentitan#7303 introduces an initial implementation of KAT tests for the DRBG functionality. The is still an outstanding issue with the generate output when running the test at the top level which is being tracked in lowrisc/opentitan#7505.