[i2c, dv] Add i2c_perf (v2)

This test verified transaction sending and receiving at max bandwidth by

 - Set access latency of fmt_fifo and rx_fifo to zero
 - Issue long 256-byte read/write back-to-back transactions
   to utilize bandwidth for data transfer
 - Clear interrupt immediately

Signed-off-by: Tung Hoang <hoang.tung@wdc.com>
diff --git a/hw/dv/sv/i2c_agent/i2c_device_driver.sv b/hw/dv/sv/i2c_agent/i2c_device_driver.sv
index 5ac642c..7917814 100644
--- a/hw/dv/sv/i2c_agent/i2c_device_driver.sv
+++ b/hw/dv/sv/i2c_agent/i2c_device_driver.sv
@@ -47,6 +47,7 @@
         RdData: begin
           `DV_CHECK_MEMBER_RANDOMIZE_FATAL(rd_data)
           rd_data_cnt++;
+          `DV_CHECK_LE(rd_data_cnt, 256);
           for (int i = 7; i >= 0; i--) begin
             cfg.vif.device_send_bit(cfg.timing_cfg, rd_data[rd_data_cnt][i]);
           end
diff --git a/hw/ip/i2c/data/i2c_testplan.hjson b/hw/ip/i2c/data/i2c_testplan.hjson
index 09ce54d..81b48b5 100644
--- a/hw/ip/i2c/data/i2c_testplan.hjson
+++ b/hw/ip/i2c/data/i2c_testplan.hjson
@@ -67,7 +67,7 @@
               - Reduce access latency for fmt_fifo and rx_fifo
               - Issue long read/write back-to-back transactions 
               - Read rx_fifo as soon as read data valid
-
+              - Clear interrupt quickly
             Checking:
               - Ensure transactions are transceivered correctly
             '''
diff --git a/hw/ip/i2c/dv/env/i2c_env.core b/hw/ip/i2c/dv/env/i2c_env.core
index 110f3b0..9a8baec 100644
--- a/hw/ip/i2c/dv/env/i2c_env.core
+++ b/hw/ip/i2c/dv/env/i2c_env.core
@@ -26,6 +26,7 @@
       - seq_lib/i2c_override_vseq.sv: {is_include_file: true}
       - seq_lib/i2c_fifo_watermark_vseq.sv: {is_include_file: true}
       - seq_lib/i2c_fifo_overflow_vseq.sv: {is_include_file: true}
+      - seq_lib/i2c_perf_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
 generate:
diff --git a/hw/ip/i2c/dv/env/i2c_env_pkg.sv b/hw/ip/i2c/dv/env/i2c_env_pkg.sv
index e03c8cc..8c86801 100644
--- a/hw/ip/i2c/dv/env/i2c_env_pkg.sv
+++ b/hw/ip/i2c/dv/env/i2c_env_pkg.sv
@@ -56,7 +56,6 @@
   parameter uint I2C_MIN_TIMING  = 1; // at least 1
   parameter uint I2C_MAX_TIMING  = 5;
   parameter uint I2C_TIME_RANGE  = I2C_MAX_TIMING - I2C_MIN_TIMING;
-  parameter uint I2C_TIMEOUT_ENB = 1;
   parameter uint I2C_MIN_TIMEOUT = 1;
   parameter uint I2C_MAX_TIMEOUT = 4;
   parameter uint I2C_MAX_RXILVL  = 7;
diff --git a/hw/ip/i2c/dv/env/i2c_scoreboard.sv b/hw/ip/i2c/dv/env/i2c_scoreboard.sv
index ce9e8cf..56f17f4 100644
--- a/hw/ip/i2c/dv/env/i2c_scoreboard.sv
+++ b/hw/ip/i2c/dv/env/i2c_scoreboard.sv
@@ -50,8 +50,7 @@
     uvm_reg   csr;
     i2c_item  sb_exp_wr_item;
     i2c_item  sb_exp_rd_item;
-    bit do_read_check = 1'b0;
-
+    bit do_read_check = 1'b0;    // TODO: Enable this bit later
     bit write = item.is_write();
 
     uvm_reg_addr_t csr_addr = get_normalized_addr(item.a_addr);
@@ -122,6 +121,7 @@
               // write transaction
               if (exp_wr_item.start && exp_wr_item.bus_op == BusOpWrite) begin
                 cfg.clk_rst_vif.wait_clks(1); // irq appears with one cycle latency
+                // TODO: Gather all irq verification in SCB instead of distribute in vseq
                 if (cfg.intr_vif.pins[FmtOverflow]) begin
                   // fmt_fifo is overflow, capture dropped data
                   exp_wr_item.fmt_ovf_data_q.push_back(fbyte);
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_base_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_base_vseq.sv
index b1302a0..08e6668 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_base_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_base_vseq.sv
@@ -22,7 +22,7 @@
   // random property
   rand uint                   fmt_fifo_access_dly;
   rand uint                   rx_fifo_access_dly;
-  rand uint                   access_intr_dly;
+  rand uint                   clear_intr_dly;
 
   rand uint                   num_trans;
   rand uint                   num_wr_bytes;
@@ -61,7 +61,9 @@
 
   // number of extra data write written to fmt to trigger interrupts
   // i.e. overflow, watermark
-  constraint num_data_ovf_c { num_data_ovf inside {[5 : 10]}; }
+  constraint num_data_ovf_c {
+    num_data_ovf inside {[I2C_RX_FIFO_DEPTH/4 : I2C_RX_FIFO_DEPTH/2]};
+  }
 
   // create uniform assertion distributions of rx_watermark interrupt
   constraint rxilvl_c {
@@ -83,7 +85,6 @@
     };
   }
   constraint num_rd_bytes_c {
-    num_rd_bytes < 128;
     num_rd_bytes dist {
       1       :/ 17,
       [2:4]   :/ 17,
@@ -94,8 +95,8 @@
     };
   }
 
-  constraint access_intr_dly_c {
-    access_intr_dly inside {[I2C_MIN_DLY:I2C_MAX_DLY]};
+  constraint clear_intr_dly_c {
+    clear_intr_dly inside {[I2C_MIN_DLY:I2C_MAX_DLY]};
   }
   constraint fmt_fifo_access_dly_c {
     fmt_fifo_access_dly inside {[I2C_MIN_DLY:I2C_MAX_DLY]};
@@ -113,7 +114,6 @@
     tsu_dat   inside { [I2C_MIN_TIMING : I2C_MAX_TIMING] };
     thd_dat   inside { [I2C_MIN_TIMING : I2C_MAX_TIMING] };
     t_timeout inside { [I2C_MIN_TIMING : I2C_MAX_TIMING] };
-    e_timeout inside { [0 : I2C_TIMEOUT_ENB] };
 
     solve t_r, tsu_dat, thd_dat before tlow;
     solve t_r                   before t_buf;
@@ -147,7 +147,7 @@
   virtual task host_init();
     bit [TL_DW-1: 0] intr_state;
 
-    `uvm_info(`gfn, "initialize i2c host registers", UVM_LOW)
+    `uvm_info(`gfn, "initialize i2c host registers", UVM_DEBUG)
     ral.ctrl.enablehost.set(1'b1);
     csr_update(ral.ctrl);
 
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_overflow_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_overflow_vseq.sv
index 3354c2a..49ce25e 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_overflow_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_overflow_vseq.sv
@@ -32,7 +32,7 @@
     `DV_CHECK_MEMBER_RANDOMIZE_FATAL(num_trans)
     for (int i = 0; i < num_trans; i++) begin
       check_fmt_overflow = 1'b1; // set to gracefully stop check_fmt_overflow_intr
-      check_rx_overflow  = 1'b1; // set to gracefully stop check_ex_overflow_intr
+      check_rx_overflow  = 1'b1; // set to gracefully stop check_rx_overflow_intr
       num_fmt_overflow   = 0;
       num_rx_overflow    = 0;
 
@@ -59,14 +59,14 @@
           // -> send read transaction -> pooling and counting rx_overflow interrupt
           // -> check write complete -> stop pooling rx_overflow interrupt
           // -> verify the number of received rx_overflow interrupt
-          // TODO: -> verify the rx_data dropped should be performed in scoreboard
+          // -> verify the rx_data dropped is performed in scoreboard
           if (check_rx_overflow) begin
             host_send_trans(.num_trans(1), .trans_type(ReadOnly));
             csr_spinwait(.ptr(ral.status.rxempty), .exp_data(1'b1));
             check_rx_overflow = 1'b0;
             `DV_CHECK_EQ(num_rx_overflow, 1)
             `uvm_info(`gfn, $sformatf("\nRun %0d, num_rx_overflow %d",
-                i, num_rx_overflow), UVM_LOW)
+                i, num_rx_overflow), UVM_DEBUG)
           end
         end
         begin
@@ -99,4 +99,4 @@
     end
   endtask : check_rx_overflow_intr
 
-endclass : i2c_fifo_overflow_vseq
\ No newline at end of file
+endclass : i2c_fifo_overflow_vseq
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_watermark_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_watermark_vseq.sv
index 471fa63..843f73f 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_watermark_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_watermark_vseq.sv
@@ -120,3 +120,4 @@
   endtask : check_rx_watermark_intr
 
 endclass : i2c_fifo_watermark_vseq
+
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_perf_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_perf_vseq.sv
new file mode 100644
index 0000000..507c5f9
--- /dev/null
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_perf_vseq.sv
@@ -0,0 +1,71 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// performance test vseq
+class i2c_perf_vseq extends i2c_rx_tx_vseq;
+  `uvm_object_utils(i2c_perf_vseq)
+  `uvm_object_new
+
+  constraint num_trans_c { num_trans inside {[10 : 16]}; }
+
+  // should have few long transactions
+  constraint num_wr_bytes_c {
+    num_wr_bytes dist {
+      1       :/ 15,
+      [2:8]   :/ 20,
+      [9:32]  :/ 15,
+      256     :/ 50
+    };
+  }
+  // num_rd_bytes = 1: read transaction length is 256b bytes
+  constraint num_rd_bytes_c {
+    num_rd_bytes dist {
+      0       :/ 50,
+      1       :/ 15,
+      [2:8]   :/ 20,
+      [9:32]  :/ 15
+    };
+  }
+  
+  // clear interrupt immediately
+  constraint clear_intr_dly_c { clear_intr_dly == 0; }
+  
+  // zero fifo access latency
+  constraint fmt_fifo_access_dly_c { fmt_fifo_access_dly == 0;}
+  constraint rx_fifo_access_dly_c  { rx_fifo_access_dly  == 0;}
+
+  // fast timing values programmed to registers
+  constraint timing_val_c {
+    thigh     == 1;
+    t_r       == 1;
+    t_f       == 1;
+    thd_sta   == 1;
+    tsu_sto   == 1;
+    tsu_dat   == 1;
+    thd_dat   == 1;
+    t_timeout == 1;
+    e_timeout == 1;
+    tsu_sta   == 1;
+    tlow      == 4;  // min:  (t_r + tsu_dat + thd_dat + 1)
+    t_buf     == 1;  // min:  (tsu_sta - t_r + 1)
+  }
+
+  task body();
+    device_init();
+    host_init();
+
+    `DV_CHECK_MEMBER_RANDOMIZE_FATAL(num_trans)
+    fork
+      begin
+        while (do_interrupt) process_interrupts();
+      end
+      begin
+        host_send_trans(num_trans);
+        do_interrupt = 1'b0; // gracefully stop process_interrupts
+      end
+    join
+  endtask : body
+
+endclass : i2c_perf_vseq
+
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_rx_tx_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_rx_tx_vseq.sv
index 593a1f7..f197374 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_rx_tx_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_rx_tx_vseq.sv
@@ -84,6 +84,9 @@
           stop  == (last_tran) ? 1'b1 : stop;
         )
         `DV_CHECK_EQ(fmt_item.stop | fmt_item.rcont, 1)
+        if (num_rd_bytes == 0) begin
+          `uvm_info(`gfn, "\nRead transaction length is 256 byte", UVM_DEBUG)
+        end
 
         // accumulate number of read byte
         total_rd_bytes += (num_rd_bytes) ? num_rd_bytes : 256;
@@ -131,6 +134,10 @@
   virtual task host_write_trans(bit last_tran);
     `DV_CHECK_MEMBER_RANDOMIZE_FATAL(num_wr_bytes)
     `DV_CHECK_MEMBER_RANDOMIZE_FATAL(wr_data)
+    if (num_wr_bytes == 256) begin
+      `uvm_info(`gfn, "\nWrite transaction length is 256 byte", UVM_DEBUG)
+    end
+
     for (int i = 1; i <= num_wr_bytes; i++) begin
       `DV_CHECK_RANDOMIZE_WITH_FATAL(fmt_item,
         start == 1'b0;
@@ -168,8 +175,8 @@
       `uvm_info(`gfn, "\nClearing rx_watermark", UVM_DEBUG)
     end
 
-    `DV_CHECK_MEMBER_RANDOMIZE_FATAL(access_intr_dly)
-    cfg.clk_rst_vif.wait_clks(access_intr_dly);
+    `DV_CHECK_MEMBER_RANDOMIZE_FATAL(clear_intr_dly)
+    cfg.clk_rst_vif.wait_clks(clear_intr_dly);
     csr_wr(.csr(ral.intr_state), .value(intr_clear));
   endtask : process_interrupts
 
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_sanity_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_sanity_vseq.sv
index 164c3d9..7b02a26 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_sanity_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_sanity_vseq.sv
@@ -7,10 +7,10 @@
   `uvm_object_utils(i2c_sanity_vseq)
   `uvm_object_new
 
-  constraint access_intr_dly_c { access_intr_dly inside {[0 : 10]}; }
-  constraint num_wr_bytes_c    { num_wr_bytes    inside {[1 : 5]}; }
-  constraint num_rd_bytes_c    { num_rd_bytes    inside {[1 : 5]}; }
-  constraint num_trans_c       { num_trans       inside {[50 : 100]}; }
+  constraint clear_intr_dly_c  { clear_intr_dly inside {[0 : 10]}; }
+  constraint num_wr_bytes_c    { num_wr_bytes   inside {[1 : 5]}; }
+  constraint num_rd_bytes_c    { num_rd_bytes   inside {[1 : 5]}; }
+  constraint num_trans_c       { num_trans      inside {[50 : 100]}; }
 
   task body();
     device_init();
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_vseq_list.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_vseq_list.sv
index 46869a4..d09394f 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_vseq_list.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_vseq_list.sv
@@ -9,4 +9,5 @@
 
 `include "i2c_override_vseq.sv"
 `include "i2c_fifo_watermark_vseq.sv"
-`include "i2c_fifo_overflow_vseq.sv"
\ No newline at end of file
+`include "i2c_fifo_overflow_vseq.sv"
+`include "i2c_perf_vseq.sv"
\ No newline at end of file
diff --git a/hw/ip/i2c/dv/i2c_sim_cfg.hjson b/hw/ip/i2c/dv/i2c_sim_cfg.hjson
index 1815d52..95dd64f 100644
--- a/hw/ip/i2c/dv/i2c_sim_cfg.hjson
+++ b/hw/ip/i2c/dv/i2c_sim_cfg.hjson
@@ -64,6 +64,13 @@
       name: i2c_fifo_overflow
       uvm_test_seq: i2c_fifo_overflow_vseq
     }
+
+    {
+      name: i2c_perf
+      // define low reseed due to long simulation time
+      reseed: 5
+      uvm_test_seq: i2c_perf_vseq
+    }
   ]
 
   // List of regressions.