data/full_repos/permissive/133480136/src/tb/tb_poly1305.v
 line:3: before: "("
1: b'%Warning-STMTDLY: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:128: Unsupported: Ignoring delay on this delayed statement.\n      #CLK_HALF_PERIOD;\n      ^\n                  ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message.\n%Warning-STMTDLY: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:143: Unsupported: Ignoring delay on this delayed statement.\n      #(CLK_PERIOD);\n      ^\n%Warning-STMTDLY: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:205: Unsupported: Ignoring delay on this delayed statement.\n      #(2 * CLK_PERIOD);\n      ^\n%Warning-STMTDLY: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:280: Unsupported: Ignoring delay on this delayed statement.\n      #(num_cycles * CLK_PERIOD);\n      ^\n%Warning-STMTDLY: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:312: Unsupported: Ignoring delay on this delayed statement.\n      #(CLK_PERIOD);\n      ^\n%Warning-STMTDLY: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:360: Unsupported: Ignoring delay on this delayed statement.\n      #(2 * CLK_PERIOD);\n      ^\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:164: Can\'t find definition of \'init_reg\' in dotted variable: \'dut.init_reg\'\n               dut.init_reg, dut.next_reg, dut.finish_reg);\n                   ^~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:164: Can\'t find definition of \'next_reg\' in dotted variable: \'dut.next_reg\'\n               dut.init_reg, dut.next_reg, dut.finish_reg);\n                                 ^~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:164: Can\'t find definition of \'finish_reg\' in dotted variable: \'dut.finish_reg\'\n               dut.init_reg, dut.next_reg, dut.finish_reg);\n                                               ^~~~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:165: Can\'t find definition of \'core_ready\' in dotted variable: \'dut.core_ready\'\n      $display("ready:    0x%01x", dut.core_ready);\n                                       ^~~~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:166: Can\'t find definition of \'core_key\' in dotted variable: \'dut.core_key\'\n      $display("key:      0x%064x", dut.core_key);\n                                        ^~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:167: Can\'t find definition of \'core_block\' in dotted variable: \'dut.core_block\'\n      $display("block:    0x%032x", dut.core_block);\n                                        ^~~~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:168: Can\'t find definition of \'blocklen_reg\' in dotted variable: \'dut.blocklen_reg\'\n      $display("blocklen: 0x%02x", dut.blocklen_reg);\n                                       ^~~~~~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:169: Can\'t find definition of \'core_mac\' in dotted variable: \'dut.core_mac\'\n      $display("mac:      0x%032x", dut.core_mac);\n                                        ^~~~~~~~\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:177: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.r_reg[0], dut.core.r_reg[1],\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:177: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.r_reg[0], dut.core.r_reg[1],\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:178: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.r_reg[2], dut.core.r_reg[3]);\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:178: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.r_reg[2], dut.core.r_reg[3]);\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:180: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.h_reg[0], dut.core.h_reg[1], dut.core.h_reg[2],\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:180: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.h_reg[0], dut.core.h_reg[1], dut.core.h_reg[2],\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:180: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.h_reg[0], dut.core.h_reg[1], dut.core.h_reg[2],\n                                                             ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:181: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.h_reg[3], dut.core.h_reg[4]);\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:181: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.h_reg[3], dut.core.h_reg[4]);\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:183: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.c_reg[0], dut.core.c_reg[1], dut.core.c_reg[2],\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:183: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.c_reg[0], dut.core.c_reg[1], dut.core.c_reg[2],\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:183: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.c_reg[0], dut.core.c_reg[1], dut.core.c_reg[2],\n                                                             ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:184: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.c_reg[3], dut.core.c_reg[4]);\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:184: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.c_reg[3], dut.core.c_reg[4]);\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:186: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.s_reg[0], dut.core.s_reg[1],\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:186: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.s_reg[0], dut.core.s_reg[1],\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:187: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.s_reg[2], dut.core.s_reg[3]);\n                       ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: data/full_repos/permissive/133480136/src/tb/tb_poly1305.v:187: Can\'t find definition of \'core\' in dotted scope/variable: \'dut.core\'\n                   dut.core.s_reg[2], dut.core.s_reg[3]);\n                                          ^~~~\n        ... Known scopes under \'dut\': <no cells found>\n%Error: Exiting due to 26 error(s), 6 warning(s)\n        ... See the manual and https://verilator.org for more assistance.\n'
module tb_poly1305();




  localparam CLK_HALF_PERIOD = 1;
  localparam CLK_PERIOD      = 2 * CLK_HALF_PERIOD;


  localparam ADDR_NAME0       = 8'h00;
  localparam ADDR_NAME1       = 8'h01;
  localparam ADDR_VERSION     = 8'h02;

  localparam ADDR_CTRL        = 8'h08;
  localparam CTRL_INIT_BIT    = 0;
  localparam CTRL_NEXT_BIT    = 1;
  localparam CTRL_FINISH_BIT  = 2;

  localparam ADDR_STATUS      = 8'h09;
  localparam STATUS_READY_BIT = 0;

  localparam ADDR_BLOCKLEN    = 8'h0a;

  localparam ADDR_KEY0        = 8'h10;
  localparam ADDR_KEY1        = 8'h11;
  localparam ADDR_KEY2        = 8'h12;
  localparam ADDR_KEY3        = 8'h13;
  localparam ADDR_KEY4        = 8'h14;
  localparam ADDR_KEY5        = 8'h15;
  localparam ADDR_KEY6        = 8'h16;
  localparam ADDR_KEY7        = 8'h17;

  localparam ADDR_BLOCK0      = 8'h20;
  localparam ADDR_BLOCK1      = 8'h21;
  localparam ADDR_BLOCK2      = 8'h22;
  localparam ADDR_BLOCK3      = 8'h23;

  localparam ADDR_MAC0        = 8'h30;
  localparam ADDR_MAC1        = 8'h31;
  localparam ADDR_MAC2        = 8'h32;
  localparam ADDR_MAC3        = 8'h33;





  reg [31 : 0]  cycle_ctr;
  reg [31 : 0]  error_ctr;
  reg [31 : 0]  tc_ctr;
  reg           tc_correct;

  reg [31 : 0]  read_data;
  reg [127 : 0] result_mac;

  reg           tb_debug;
  reg           tb_core_state;

  reg           tb_clk;
  reg           tb_reset_n;
  reg           tb_cs;
  reg           tb_we;
  reg [7  : 0]  tb_address;
  reg [31 : 0]  tb_write_data;
  wire [31 : 0] tb_read_data;





  poly1305 dut(
               .clk(tb_clk),
               .reset_n(tb_reset_n),
               .cs(tb_cs),
               .we(tb_we),
               .address(tb_address),
               .write_data(tb_write_data),
               .read_data(tb_read_data)
              );







  always
    begin : clk_gen
      #CLK_HALF_PERIOD;
      tb_clk = !tb_clk;
    end








  always
    begin : sys_monitor
      cycle_ctr = cycle_ctr + 1;

      #(CLK_PERIOD);

      if (tb_debug)
        begin
          dump_dut_state();
        end
    end







  task dump_dut_state;
    begin
      $display("");
      $display("================================================================");
      $display("cycle:  0x%016x", cycle_ctr);
      $display("DUT internals:");
      $display("ctrl:     init_reg = 0x%01x, next_reg = 0x%01x, finish_reg = 0x%01x",
               dut.init_reg, dut.next_reg, dut.finish_reg);
      $display("ready:    0x%01x", dut.core_ready);
      $display("key:      0x%064x", dut.core_key);
      $display("block:    0x%032x", dut.core_block);
      $display("blocklen: 0x%02x", dut.blocklen_reg);
      $display("mac:      0x%032x", dut.core_mac);

      if (tb_core_state)
        begin
          $display("");
          $display("Internal state:");
          $display("---------------");
          $display("r:     0x%08x_%08x_%08x_%08x",
                   dut.core.r_reg[0], dut.core.r_reg[1],
                   dut.core.r_reg[2], dut.core.r_reg[3]);
          $display("h:     0x%08x_%08x_%08x_%08x_%08x",
                   dut.core.h_reg[0], dut.core.h_reg[1], dut.core.h_reg[2],
                   dut.core.h_reg[3], dut.core.h_reg[4]);
          $display("c:     0x%08x_%08x_%08x_%08x_%08x",
                   dut.core.c_reg[0], dut.core.c_reg[1], dut.core.c_reg[2],
                   dut.core.c_reg[3], dut.core.c_reg[4]);
          $display("s:     0x%08x_%08x_%08x_%08x",
                   dut.core.s_reg[0], dut.core.s_reg[1],
                   dut.core.s_reg[2], dut.core.s_reg[3]);
        end

      $display("================================================================");
      $display("");
    end
  endtask







  task reset_dut;
    begin
      $display("TB: Resetting dut.");
      tb_reset_n = 0;
      #(2 * CLK_PERIOD);
      tb_reset_n = 1;
    end
  endtask







  task display_test_results;
    begin
      $display("");
      if (error_ctr == 0)
        begin
          $display("%02d test completed. All test cases completed successfully.", tc_ctr);
        end
      else
        begin
          $display("%02d tests completed - %02d test cases did not complete successfully.",
                   tc_ctr, error_ctr);
        end
    end
  endtask








  task init_sim;
    begin
      cycle_ctr     = 0;
      error_ctr     = 0;
      tc_ctr        = 0;
      tb_debug      = 0;
      tb_core_state = 0;
      tb_clk        = 0;
      tb_reset_n    = 1;

      tb_cs         = 0;
      tb_we         = 0;
      tb_address    = 8'h0;
      tb_write_data = 32'h0;
    end
  endtask





  task inc_tc_ctr;
    tc_ctr = tc_ctr + 1;
  endtask





  task inc_error_ctr;
    error_ctr = error_ctr + 1;
  endtask







  task pause_finish(input [31 : 0] num_cycles);
    begin
      $display("Pausing for %04d cycles and then finishing hard.", num_cycles);
      #(num_cycles * CLK_PERIOD);
      $finish;
    end
  endtask







  task wait_ready;
    begin : wready
      read_word(ADDR_STATUS);
      while (read_data == 0)
        read_word(ADDR_STATUS);
    end
  endtask









  task read_word(input [11 : 0]  address);
    begin
      tb_address = address;
      tb_cs = 1;
      tb_we = 0;
      #(CLK_PERIOD);
      read_data = tb_read_data;
      tb_cs = 0;

      if (tb_debug)
        begin
          $display("*** Reading 0x%08x from 0x%02x.", read_data, address);
          $display("");
        end
    end
  endtask





  task read_mac;
    begin
      read_word(ADDR_MAC0);
      result_mac[127 : 096] = read_data;
      read_word(ADDR_MAC1);
      result_mac[095 : 064] = read_data;
      read_word(ADDR_MAC2);
      result_mac[063 : 032] = read_data;
      read_word(ADDR_MAC3);
      result_mac[031 : 000] = read_data;
    end
  endtask







  task write_word(input [11 : 0] address,
                  input [31 : 0] word);
    begin
      if (tb_debug)
        begin
          $display("*** Writing 0x%08x to 0x%02x.", word, address);
          $display("");
        end

      tb_address = address;
      tb_write_data = word;
      tb_cs = 1;
      tb_we = 1;
      #(2 * CLK_PERIOD);
      tb_cs = 0;
      tb_we = 0;
    end
  endtask





  task write_key(input [255 : 0] key);
    begin
      if (tb_debug)
        begin
          $display("Writing key to the DUT: 0x%064x", key);
        end

      write_word(ADDR_KEY0, key[255  : 224]);
      write_word(ADDR_KEY1, key[223  : 192]);
      write_word(ADDR_KEY2, key[191  : 160]);
      write_word(ADDR_KEY3, key[159  : 128]);
      write_word(ADDR_KEY4, key[127  :  96]);
      write_word(ADDR_KEY5, key[95   :  64]);
      write_word(ADDR_KEY6, key[63   :  32]);
      write_word(ADDR_KEY7, key[31   :   0]);
    end
  endtask





  task write_block(input [127 : 0] block);
    begin
      if (tb_debug)
        begin
          $display("Writing block to the DUT: 0x%032x", block);
        end

      write_word(ADDR_BLOCK0, block[127  :  96]);
      write_word(ADDR_BLOCK1, block[95   :  64]);
      write_word(ADDR_BLOCK2, block[63   :  32]);
      write_word(ADDR_BLOCK3, block[31   :   0]);
    end
  endtask





  task check_mac(input [127 : 0] expected);
    begin
      read_mac();

      if (result_mac == expected)
        $display("*** check_mac: Correct MAC generated.");
      else begin
        $display("*** check_mac: Error. Incorrect MAC generated.");
        $display("*** check_mac: Expected: 0x%032x", expected);
        $display("*** check_mac: Got:      0x%032x", result_mac);
        error_ctr = error_ctr + 1;
      end
    end
  endtask









  task test_rfc8439;
    begin : test_rfc8439
      $display("*** test_rfc8439 started.");
      inc_tc_ctr();

      tb_debug = 0;

      write_key(256'h85d6be78_57556d33_7f4452fe_42d506a8_0103808a_fb0db2fd_4abff6af_4149f51b);
      write_block(128'h0);

      $display("*** test_rfc8439: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();
      $display("*** test_rfc8439: init() should be completed.");

      $display("*** test_rfc8439: Loading the first 16 bytes of message and running next().");
      write_block(128'h43727970_746f6772_61706869_6320466f);
      write_word(ADDR_BLOCKLEN, 32'h10);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_rfc8439: next() should be completed.");

      $display("*** test_rfc8439: Loading the second 16 bytes and running next().");
      write_block(128'h72756d20_52657365_61726368_2047726f);
      write_word(ADDR_BLOCKLEN, 32'h10);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_rfc8439: next() should be completed.");


      $display("*** test_rfc8439: Loading the final 2 bytes and running next().");
      write_block(128'h75700000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h2);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_rfc8439: next() should be completed.");


      $display("*** test_rfc8439: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();
      $display("*** test_rfc8439: finish() should be completed.");

      $display("*** test_rfc8439: Checking the generated MAC.");
      check_mac(128'ha8061dc1_305136c6_c22b8baf_0c0127a9);

      tb_debug = 0;

      $display("*** test_rfc8439 completed.\n");
    end
  endtask






  task test_bytes0;
    begin : test_bytes0
      $display("*** test_bytes0 started.");
      inc_tc_ctr();

      tb_debug = 0;

      write_key(256'h85d6be78_57556d33_7f4452fe_42d506a8_0103808a_fb0db2fd_4abff6af_4149f51b);
      write_block(128'h0);

      $display("*** test_bytes0: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();
      $display("*** test_bytes0: init() should be completed.");

      $display("*** test_bytes0: Loading the zero byte message and running next().");
      write_block(128'h00000000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h0);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_bytes1: next() should be completed.");

      $display("*** test_bytes0: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();
      $display("*** test_bytes0: finish() should be completed.");

      $display("*** test_bytes0: Checking the generated MAC.");
      check_mac(128'h0103808afb0db2fd4abff6af4149f51b);

      tb_debug = 0;

      $display("*** test_bytes0 completed.\n");
    end
  endtask







  task test_bytes1;
    begin : test_bytes1
      $display("*** test_bytes1 started.");
      inc_tc_ctr();

      tb_debug = 0;

      write_key(256'h85d6be78_57556d33_7f4452fe_42d506a8_0103808a_fb0db2fd_4abff6af_4149f51b);
      write_block(128'h0);

      $display("*** test_bytes1: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();
      $display("*** test_bytes1: init() should be completed.");

      $display("*** test_bytes1: Loading the one byte message and running next().");
      write_block(128'h31000000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h1);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_bytes1: next() should be completed.");

      $display("*** test_bytes1: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();
      $display("*** test_bytes1: finish() should be completed.");

      $display("*** test_bytes1: Checking the generated MAC.");
      check_mac(128'h8097ddf5_19b7f412_0b57fabf_925a19ac);

      tb_debug = 0;

      $display("*** test_bytes1 completed.\n");
    end
  endtask





  task test_long;
    begin : test_long
      integer i;

      $display("*** test_long started.");
      inc_tc_ctr();

      tb_debug      = 0;
      tb_core_state = 0;

      write_key(256'hf3000000_00000000_00000000_0000003f_3f000000_00000000_00000000_000000f3);
      write_block(128'h0);

      $display("*** test_long: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();

      $display("*** test_long: Processing 64 complete blocks.");
      write_block(128'hffffffff_ffffffff_ffffffff_ffffffff);
      write_word(ADDR_BLOCKLEN, 32'h10);
      for (i = 0 ; i < 64 ; i = i + 1)
        begin
          $display("*** testcase_long: Processing block %0d", i);
          write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
          wait_ready();
        end

      $display("*** test_long: Processing the final single byte block.");
      write_block(128'h01000000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h1);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();

      $display("*** test_long: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();

      $display("*** test_long: Checking the generated MAC.");
      check_mac(128'hdc0964e5ce9cd7d9a7571fafa5dc0473);

      tb_debug      = 0;
      tb_core_state = 0;

      $display("*** test_long completed.\n");
    end
  endtask







  initial
    begin : main
      $display("*** Testbench for poly1305 started ***");
      $display("");

      init_sim();

      reset_dut();

      test_bytes0();
      test_bytes1();
      test_rfc8439();
      test_long();

      display_test_results();

      $display("*** Testbench for poly1305 done ***");
      $finish;
    end

endmodule
module tb_poly1305();





  localparam CLK_HALF_PERIOD = 1;
  localparam CLK_PERIOD      = 2 * CLK_HALF_PERIOD;


  localparam ADDR_NAME0       = 8'h00;
  localparam ADDR_NAME1       = 8'h01;
  localparam ADDR_VERSION     = 8'h02;

  localparam ADDR_CTRL        = 8'h08;
  localparam CTRL_INIT_BIT    = 0;
  localparam CTRL_NEXT_BIT    = 1;
  localparam CTRL_FINISH_BIT  = 2;

  localparam ADDR_STATUS      = 8'h09;
  localparam STATUS_READY_BIT = 0;

  localparam ADDR_BLOCKLEN    = 8'h0a;

  localparam ADDR_KEY0        = 8'h10;
  localparam ADDR_KEY1        = 8'h11;
  localparam ADDR_KEY2        = 8'h12;
  localparam ADDR_KEY3        = 8'h13;
  localparam ADDR_KEY4        = 8'h14;
  localparam ADDR_KEY5        = 8'h15;
  localparam ADDR_KEY6        = 8'h16;
  localparam ADDR_KEY7        = 8'h17;

  localparam ADDR_BLOCK0      = 8'h20;
  localparam ADDR_BLOCK1      = 8'h21;
  localparam ADDR_BLOCK2      = 8'h22;
  localparam ADDR_BLOCK3      = 8'h23;

  localparam ADDR_MAC0        = 8'h30;
  localparam ADDR_MAC1        = 8'h31;
  localparam ADDR_MAC2        = 8'h32;
  localparam ADDR_MAC3        = 8'h33;





  reg [31 : 0]  cycle_ctr;
  reg [31 : 0]  error_ctr;
  reg [31 : 0]  tc_ctr;
  reg           tc_correct;

  reg [31 : 0]  read_data;
  reg [127 : 0] result_mac;

  reg           tb_debug;
  reg           tb_core_state;

  reg           tb_clk;
  reg           tb_reset_n;
  reg           tb_cs;
  reg           tb_we;
  reg [7  : 0]  tb_address;
  reg [31 : 0]  tb_write_data;
  wire [31 : 0] tb_read_data;





  poly1305 dut(
               .clk(tb_clk),
               .reset_n(tb_reset_n),
               .cs(tb_cs),
               .we(tb_we),
               .address(tb_address),
               .write_data(tb_write_data),
               .read_data(tb_read_data)
              );







  always
    begin : clk_gen
      #CLK_HALF_PERIOD;
      tb_clk = !tb_clk;
    end








  always
    begin : sys_monitor
      cycle_ctr = cycle_ctr + 1;

      #(CLK_PERIOD);

      if (tb_debug)
        begin
          dump_dut_state();
        end
    end







  task dump_dut_state;
    begin
      $display("");
      $display("================================================================");
      $display("cycle:  0x%016x", cycle_ctr);
      $display("DUT internals:");
      $display("ctrl:     init_reg = 0x%01x, next_reg = 0x%01x, finish_reg = 0x%01x",
               dut.init_reg, dut.next_reg, dut.finish_reg);
      $display("ready:    0x%01x", dut.core_ready);
      $display("key:      0x%064x", dut.core_key);
      $display("block:    0x%032x", dut.core_block);
      $display("blocklen: 0x%02x", dut.blocklen_reg);
      $display("mac:      0x%032x", dut.core_mac);

      if (tb_core_state)
        begin
          $display("");
          $display("Internal state:");
          $display("---------------");
          $display("r:     0x%08x_%08x_%08x_%08x",
                   dut.core.r_reg[0], dut.core.r_reg[1],
                   dut.core.r_reg[2], dut.core.r_reg[3]);
          $display("h:     0x%08x_%08x_%08x_%08x_%08x",
                   dut.core.h_reg[0], dut.core.h_reg[1], dut.core.h_reg[2],
                   dut.core.h_reg[3], dut.core.h_reg[4]);
          $display("c:     0x%08x_%08x_%08x_%08x_%08x",
                   dut.core.c_reg[0], dut.core.c_reg[1], dut.core.c_reg[2],
                   dut.core.c_reg[3], dut.core.c_reg[4]);
          $display("s:     0x%08x_%08x_%08x_%08x",
                   dut.core.s_reg[0], dut.core.s_reg[1],
                   dut.core.s_reg[2], dut.core.s_reg[3]);
        end

      $display("================================================================");
      $display("");
    end
  endtask







  task reset_dut;
    begin
      $display("TB: Resetting dut.");
      tb_reset_n = 0;
      #(2 * CLK_PERIOD);
      tb_reset_n = 1;
    end
  endtask







  task display_test_results;
    begin
      $display("");
      if (error_ctr == 0)
        begin
          $display("%02d test completed. All test cases completed successfully.", tc_ctr);
        end
      else
        begin
          $display("%02d tests completed - %02d test cases did not complete successfully.",
                   tc_ctr, error_ctr);
        end
    end
  endtask








  task init_sim;
    begin
      cycle_ctr     = 0;
      error_ctr     = 0;
      tc_ctr        = 0;
      tb_debug      = 0;
      tb_core_state = 0;
      tb_clk        = 0;
      tb_reset_n    = 1;

      tb_cs         = 0;
      tb_we         = 0;
      tb_address    = 8'h0;
      tb_write_data = 32'h0;
    end
  endtask





  task inc_tc_ctr;
    tc_ctr = tc_ctr + 1;
  endtask





  task inc_error_ctr;
    error_ctr = error_ctr + 1;
  endtask







  task pause_finish(input [31 : 0] num_cycles);
    begin
      $display("Pausing for %04d cycles and then finishing hard.", num_cycles);
      #(num_cycles * CLK_PERIOD);
      $finish;
    end
  endtask







  task wait_ready;
    begin : wready
      read_word(ADDR_STATUS);
      while (read_data == 0)
        read_word(ADDR_STATUS);
    end
  endtask









  task read_word(input [11 : 0]  address);
    begin
      tb_address = address;
      tb_cs = 1;
      tb_we = 0;
      #(CLK_PERIOD);
      read_data = tb_read_data;
      tb_cs = 0;

      if (tb_debug)
        begin
          $display("*** Reading 0x%08x from 0x%02x.", read_data, address);
          $display("");
        end
    end
  endtask





  task read_mac;
    begin
      read_word(ADDR_MAC0);
      result_mac[127 : 096] = read_data;
      read_word(ADDR_MAC1);
      result_mac[095 : 064] = read_data;
      read_word(ADDR_MAC2);
      result_mac[063 : 032] = read_data;
      read_word(ADDR_MAC3);
      result_mac[031 : 000] = read_data;
    end
  endtask







  task write_word(input [11 : 0] address,
                  input [31 : 0] word);
    begin
      if (tb_debug)
        begin
          $display("*** Writing 0x%08x to 0x%02x.", word, address);
          $display("");
        end

      tb_address = address;
      tb_write_data = word;
      tb_cs = 1;
      tb_we = 1;
      #(2 * CLK_PERIOD);
      tb_cs = 0;
      tb_we = 0;
    end
  endtask





  task write_key(input [255 : 0] key);
    begin
      if (tb_debug)
        begin
          $display("Writing key to the DUT: 0x%064x", key);
        end

      write_word(ADDR_KEY0, key[255  : 224]);
      write_word(ADDR_KEY1, key[223  : 192]);
      write_word(ADDR_KEY2, key[191  : 160]);
      write_word(ADDR_KEY3, key[159  : 128]);
      write_word(ADDR_KEY4, key[127  :  96]);
      write_word(ADDR_KEY5, key[95   :  64]);
      write_word(ADDR_KEY6, key[63   :  32]);
      write_word(ADDR_KEY7, key[31   :   0]);
    end
  endtask





  task write_block(input [127 : 0] block);
    begin
      if (tb_debug)
        begin
          $display("Writing block to the DUT: 0x%032x", block);
        end

      write_word(ADDR_BLOCK0, block[127  :  96]);
      write_word(ADDR_BLOCK1, block[95   :  64]);
      write_word(ADDR_BLOCK2, block[63   :  32]);
      write_word(ADDR_BLOCK3, block[31   :   0]);
    end
  endtask





  task check_mac(input [127 : 0] expected);
    begin
      read_mac();

      if (result_mac == expected)
        $display("*** check_mac: Correct MAC generated.");
      else begin
        $display("*** check_mac: Error. Incorrect MAC generated.");
        $display("*** check_mac: Expected: 0x%032x", expected);
        $display("*** check_mac: Got:      0x%032x", result_mac);
        error_ctr = error_ctr + 1;
      end
    end
  endtask









  task test_rfc8439;
    begin : test_rfc8439
      $display("*** test_rfc8439 started.");
      inc_tc_ctr();

      tb_debug = 0;

      write_key(256'h85d6be78_57556d33_7f4452fe_42d506a8_0103808a_fb0db2fd_4abff6af_4149f51b);
      write_block(128'h0);

      $display("*** test_rfc8439: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();
      $display("*** test_rfc8439: init() should be completed.");

      $display("*** test_rfc8439: Loading the first 16 bytes of message and running next().");
      write_block(128'h43727970_746f6772_61706869_6320466f);
      write_word(ADDR_BLOCKLEN, 32'h10);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_rfc8439: next() should be completed.");

      $display("*** test_rfc8439: Loading the second 16 bytes and running next().");
      write_block(128'h72756d20_52657365_61726368_2047726f);
      write_word(ADDR_BLOCKLEN, 32'h10);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_rfc8439: next() should be completed.");


      $display("*** test_rfc8439: Loading the final 2 bytes and running next().");
      write_block(128'h75700000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h2);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_rfc8439: next() should be completed.");


      $display("*** test_rfc8439: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();
      $display("*** test_rfc8439: finish() should be completed.");

      $display("*** test_rfc8439: Checking the generated MAC.");
      check_mac(128'ha8061dc1_305136c6_c22b8baf_0c0127a9);

      tb_debug = 0;

      $display("*** test_rfc8439 completed.\n");
    end
  endtask






  task test_bytes0;
    begin : test_bytes0
      $display("*** test_bytes0 started.");
      inc_tc_ctr();

      tb_debug = 0;

      write_key(256'h85d6be78_57556d33_7f4452fe_42d506a8_0103808a_fb0db2fd_4abff6af_4149f51b);
      write_block(128'h0);

      $display("*** test_bytes0: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();
      $display("*** test_bytes0: init() should be completed.");

      $display("*** test_bytes0: Loading the zero byte message and running next().");
      write_block(128'h00000000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h0);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_bytes1: next() should be completed.");

      $display("*** test_bytes0: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();
      $display("*** test_bytes0: finish() should be completed.");

      $display("*** test_bytes0: Checking the generated MAC.");
      check_mac(128'h0103808afb0db2fd4abff6af4149f51b);

      tb_debug = 0;

      $display("*** test_bytes0 completed.\n");
    end
  endtask







  task test_bytes1;
    begin : test_bytes1
      $display("*** test_bytes1 started.");
      inc_tc_ctr();

      tb_debug = 0;

      write_key(256'h85d6be78_57556d33_7f4452fe_42d506a8_0103808a_fb0db2fd_4abff6af_4149f51b);
      write_block(128'h0);

      $display("*** test_bytes1: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();
      $display("*** test_bytes1: init() should be completed.");

      $display("*** test_bytes1: Loading the one byte message and running next().");
      write_block(128'h31000000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h1);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();
      $display("*** test_bytes1: next() should be completed.");

      $display("*** test_bytes1: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();
      $display("*** test_bytes1: finish() should be completed.");

      $display("*** test_bytes1: Checking the generated MAC.");
      check_mac(128'h8097ddf5_19b7f412_0b57fabf_925a19ac);

      tb_debug = 0;

      $display("*** test_bytes1 completed.\n");
    end
  endtask





  task test_long;
    begin : test_long
      integer i;

      $display("*** test_long started.");
      inc_tc_ctr();

      tb_debug      = 0;
      tb_core_state = 0;

      write_key(256'hf3000000_00000000_00000000_0000003f_3f000000_00000000_00000000_000000f3);
      write_block(128'h0);

      $display("*** test_long: Running init() with the RFC key.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_INIT_BIT));
      wait_ready();

      $display("*** test_long: Processing 64 complete blocks.");
      write_block(128'hffffffff_ffffffff_ffffffff_ffffffff);
      write_word(ADDR_BLOCKLEN, 32'h10);
      for (i = 0 ; i < 64 ; i = i + 1)
        begin
          $display("*** testcase_long: Processing block %0d", i);
          write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
          wait_ready();
        end

      $display("*** test_long: Processing the final single byte block.");
      write_block(128'h01000000_00000000_00000000_00000000);
      write_word(ADDR_BLOCKLEN, 32'h1);
      write_word(ADDR_CTRL, (32'h1 << CTRL_NEXT_BIT));
      wait_ready();

      $display("*** test_long: running finish() to get the MAC.");
      write_word(ADDR_CTRL, (32'h1 << CTRL_FINISH_BIT));
      wait_ready();

      $display("*** test_long: Checking the generated MAC.");
      check_mac(128'hdc0964e5ce9cd7d9a7571fafa5dc0473);

      tb_debug      = 0;
      tb_core_state = 0;

      $display("*** test_long completed.\n");
    end
  endtask







  initial
    begin : main
      $display("*** Testbench for poly1305 started ***");
      $display("");

      init_sim();

      reset_dut();

      test_bytes0();
      test_bytes1();
      test_rfc8439();
      test_long();

      display_test_results();

      $display("*** Testbench for poly1305 done ***");
      $finish;
    end

endmodule