[i2c, dv] Add i2c_stretch_timeout and i2c_fifo_full tests (v2)

1) i2c_stretch_timeout: stretch_timeout interrupt is aggressively trigerred and verified.
 - Add i2c_stretch_timeout_vseq
 - Update i2c_testplan.md
 - Fix invalid format programmed to fmt_fifo (i2c_rx_tx_vseq.sv)
 - Refactor code and clean nits

2) i2c_fifo_full: verify full status of both rx_fifo and fmt_fifo
 - Add i2c_fifo_full_vseq
 - Update i2c_testplan.md

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 7917814..e87628d 100644
--- a/hw/dv/sv/i2c_agent/i2c_device_driver.sv
+++ b/hw/dv/sv/i2c_agent/i2c_device_driver.sv
@@ -15,7 +15,7 @@
 
   virtual task get_and_drive();
     uint num_stretch_host_clks;
-    uint rd_data_cnt = 0;
+    bit [7:0] rd_data_cnt = 8'd0;
     i2c_item rsp_item;
 
     @(posedge cfg.vif.rst_ni);
@@ -45,12 +45,12 @@
           join
         end
         RdData: begin
-          `DV_CHECK_MEMBER_RANDOMIZE_FATAL(rd_data)
-          rd_data_cnt++;
-          `DV_CHECK_LE(rd_data_cnt, 256);
+          if (rd_data_cnt == 8'd0) `DV_CHECK_MEMBER_RANDOMIZE_FATAL(rd_data)
           for (int i = 7; i >= 0; i--) begin
             cfg.vif.device_send_bit(cfg.timing_cfg, rd_data[rd_data_cnt][i]);
           end
+          // rd_data_cnt is rollled back (no overflow) after reading 256 bytes
+          rd_data_cnt++;
           `uvm_info(`gfn, $sformatf("driver, trans %0d, byte %0d  %0x",
               rsp_item.tran_id, rsp_item.num_data+1, rd_data[rd_data_cnt]), UVM_DEBUG)
         end
diff --git a/hw/dv/sv/i2c_agent/i2c_driver.sv b/hw/dv/sv/i2c_agent/i2c_driver.sv
index 5c05325..f445fd2 100644
--- a/hw/dv/sv/i2c_agent/i2c_driver.sv
+++ b/hw/dv/sv/i2c_agent/i2c_driver.sv
@@ -10,11 +10,9 @@
   virtual task reset_signals();
     `uvm_info(`gfn, "driver in reset progress", UVM_HIGH)
     @(negedge cfg.vif.rst_ni);
-    cfg.vif.scl_o <= 1'b0;
-    cfg.vif.sda_o <= 1'b0;
-    @(posedge cfg.vif.rst_ni);
     cfg.vif.scl_o <= 1'b1;
     cfg.vif.sda_o <= 1'b1;
+    @(posedge cfg.vif.rst_ni);
     `uvm_info(`gfn, "driver out of reset", UVM_HIGH)
   endtask : reset_signals
 
diff --git a/hw/dv/sv/i2c_agent/i2c_item.sv b/hw/dv/sv/i2c_agent/i2c_item.sv
index dfabc9b..7319b3c 100644
--- a/hw/dv/sv/i2c_agent/i2c_item.sv
+++ b/hw/dv/sv/i2c_agent/i2c_item.sv
@@ -26,10 +26,8 @@
   constraint fbyte_c     { fbyte      inside {[0 : 127]}; }
   constraint rcont_c     {
      solve read, stop before rcont;
-     if (read) {
-       // for read request, rcont and stop must be complementary set
-       rcont  == ~stop;
-     }
+     // for read request, rcont and stop must be complementary set
+     read -> rcont == ~stop;
   }
 
   `uvm_object_utils_begin(i2c_item)
diff --git a/hw/ip/i2c/data/i2c_testplan.hjson b/hw/ip/i2c/data/i2c_testplan.hjson
index 81b48b5..4e7ec0f 100644
--- a/hw/ip/i2c/data/i2c_testplan.hjson
+++ b/hw/ip/i2c/data/i2c_testplan.hjson
@@ -167,35 +167,36 @@
       tests: []
     }
     {
-      name: fmt_rx_fifo_full
+      name: fifo_full
       desc: '''
             Test fmt_fifo and rx_fifo in full states.
 
             Stimulus:
-              - Send enough read requests, not read data out,
-                then stop until both fmt and rx fifo is full
+              - Send enough read and write requests to fmt_fifo
+              - Hold reading data from rx_fifo until rx fifo is full
 
             Checking:
               - Check fifo full states by reading status register
             '''
       milestone: V2
-      tests: []
+      tests: ["i2c_fifo_full"]
     }
     {
-      name: rx_timeout
+      name: stretch_timeout,
       desc: '''
-            Test rx_timeout state.
+            Test host clock stretching.
 
             Stimulus:
-              - Program timeout enable bit into timeout_ctrl register
+              - Set timeout enable bit into timeout_ctrl register
               - Program timeout values (higher than host scl clock pulse) into timeout_ctrl register
-              - Configure agent to pull down target(device) scl after the bit 9 (acknowledge bit) is transmitted
+              - Configure agent to pull down target (device) scl after the bit 9 (ACK) is transmitted
 
             Checking:
-              - Ensure intr_stretch_timeout interrupt is asserted
+              - Ensure stretch_timeout interrupt is asserted
+              - Ensure receving the correct number of stretch_timeout interrupt
             '''
       milestone: V2
-      tests: []
+      tests: ["i2c_stretch_timeout"]
     }
     {
       name: rx_oversample
diff --git a/hw/ip/i2c/dv/env/i2c_env.core b/hw/ip/i2c/dv/env/i2c_env.core
index 9a8baec..1afdf06 100644
--- a/hw/ip/i2c/dv/env/i2c_env.core
+++ b/hw/ip/i2c/dv/env/i2c_env.core
@@ -26,7 +26,9 @@
       - 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_fifo_full_vseq.sv: {is_include_file: true}
       - seq_lib/i2c_perf_vseq.sv: {is_include_file: true}
+      - seq_lib/i2c_stretch_timeout_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 8c86801..08d3909 100644
--- a/hw/ip/i2c/dv/env/i2c_env_pkg.sv
+++ b/hw/ip/i2c/dv/env/i2c_env_pkg.sv
@@ -45,8 +45,8 @@
   parameter uint I2C_RX_FIFO_DEPTH  = 32;
 
   // for constrains
-  parameter uint I2C_MIN_TRAN    = 10;
-  parameter uint I2C_MAX_TRAN    = 20;
+  parameter uint I2C_MIN_TRAN    = 30;
+  parameter uint I2C_MAX_TRAN    = 50;
   parameter uint I2C_MIN_ADDR    = 0;
   parameter uint I2C_MAX_ADDR    = 127;
   parameter uint I2C_MIN_DLY     = 0;
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 08e6668..f545a3d 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
@@ -68,12 +68,8 @@
   // create uniform assertion distributions of rx_watermark interrupt
   constraint rxilvl_c {
     rxilvl dist {
-      0     :/ 17,
-      1     :/ 17,
-      2     :/ 17,
-      3     :/ 16,
-      4     :/ 17,
-      [5:7] :/ 16
+      [0:4] :/ 5,
+      [5:7] :/ 1
     };
   }
   constraint num_wr_bytes_c {
@@ -81,17 +77,19 @@
       1       :/ 1,
       [2:4]   :/ 1,
       [5:8]   :/ 1,
-      [9:20]  :/ 1
+      [9:31]  :/ 1,
+      32      :/ 1
     };
   }
   constraint num_rd_bytes_c {
+    num_rd_bytes < 256;
     num_rd_bytes dist {
-      1       :/ 17,
-      [2:4]   :/ 17,
-      [5:8]   :/ 17,
-      [9:16]  :/ 16,
-      [17:30] :/ 17,
-      31      :/ 16
+      1       :/ 1,
+      [2:4]   :/ 1,
+      [5:8]   :/ 1,
+      [9:16]  :/ 1,
+      [17:31] :/ 1,
+      32      :/ 1
     };
   }
 
@@ -105,6 +103,10 @@
     rx_fifo_access_dly inside {[I2C_MIN_DLY:I2C_MAX_DLY]};
   }
 
+  constraint t_timeout_c {
+    t_timeout inside { [I2C_MIN_TIMING : I2C_MAX_TIMING] };
+  }
+
   constraint timing_val_c {
     thigh     inside { [I2C_MIN_TIMING : I2C_MAX_TIMING] };
     t_r       inside { [I2C_MIN_TIMING : I2C_MAX_TIMING] };
@@ -113,7 +115,6 @@
     tsu_sto   inside { [I2C_MIN_TIMING : I2C_MAX_TIMING] };
     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] };
 
     solve t_r, tsu_dat, thd_dat before tlow;
     solve t_r                   before t_buf;
@@ -237,7 +238,7 @@
               timing_cfg.tClockPulse + timing_cfg.tHoldBit);
   endfunction : get_byte_latency
 
-  virtual task program_format_flag(i2c_item item, string msg="");
+  virtual task program_format_flag(i2c_item item, string msg = "", bit en_print = 1'b0);
     bit fmtfull;
 
     ral.fdata.nakok.set(item.nakok);
@@ -247,22 +248,22 @@
     ral.fdata.start.set(item.start);
     ral.fdata.fbyte.set(item.fbyte);
     // en_fmt_underflow is set to ensure no write data overflow with fmt_fifo
-    // regardless en_fmt_underflow, the last data (consist of STOP bit) must be
+    // regardless en_fmt_underflow set/unset, the last data (consist of STOP bit) must be
     // pushed into fmt_fifo to safely complete transaction
     if (!cfg.en_fmt_overflow || fmt_item.stop) begin
       csr_spinwait(.ptr(ral.status.fmtfull), .exp_data(1'b0));
     end
-    // if fmt_overflow irq is triggered it must be cleared before new fmt data is program
+    // if fmt_overflow irq is triggered it must be cleared before new fmt data is programmed
     // otherwise, scoreboard can drop this data while fmt_fifo is not full
     wait(!cfg.intr_vif.pins[FmtOverflow]);
     // program fmt_fifo
     csr_update(.csr(ral.fdata));
     `DV_CHECK_MEMBER_RANDOMIZE_FATAL(fmt_fifo_access_dly)
     cfg.clk_rst_vif.wait_clks(fmt_fifo_access_dly);
-    print_format_flag(item, msg);
+    print_format_flag(item, msg, en_print);
   endtask : program_format_flag
 
-  task print_format_flag(i2c_item item, string msg = "");
+  task print_format_flag(i2c_item item, string msg = "", bit en_print = 1'b0);
     string str;
 
     str = {str, $sformatf("\n%s, format flags 0x%h \n", msg,
@@ -279,7 +280,7 @@
       str = {str, $sformatf("  | %5d | %5d | %5d | %5d | %5d | %8x |",
           item.nakok, item.rcont, item.read, item.stop, item.start, item.fbyte)};
     end
-    `uvm_info(`gfn, $sformatf("%s", str), UVM_DEBUG)
+    if (en_print) `uvm_info(`gfn, $sformatf("%s", str), UVM_LOW)
   endtask : print_format_flag
 
 endclass : i2c_base_vseq
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_common_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_common_vseq.sv
index f964d3c..01f40ab 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_common_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_common_vseq.sv
@@ -5,9 +5,7 @@
 class i2c_common_vseq extends i2c_base_vseq;
   `uvm_object_utils(i2c_common_vseq)
 
-  constraint num_trans_c {
-    num_trans inside {[1:2]};
-  }
+  constraint num_trans_c { num_trans inside {[1:2]}; }
 
   `uvm_object_new
 
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_full_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_full_vseq.sv
new file mode 100644
index 0000000..ccd1fc4
--- /dev/null
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_fifo_full_vseq.sv
@@ -0,0 +1,55 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// basic fifo_full test vseq
+class i2c_fifo_full_vseq extends i2c_sanity_vseq;
+  `uvm_object_utils(i2c_fifo_full_vseq)
+  `uvm_object_new
+
+  // fast write data to fmt_fifo to quickly trigger fmt_watermark interrupt
+  constraint fmt_fifo_access_dly_c { fmt_fifo_access_dly == 0;}
+
+  // fast read data from rd_fifo to quickly finish simulation (increasing sim. performance)
+  constraint rx_fifo_access_dly_c { rx_fifo_access_dly == 0;}
+
+  // write transaction length is more than fmt_fifo depth to fill up fmt_fifo
+  constraint num_wr_bytes_c {
+    solve num_data_ovf before num_wr_bytes;
+    num_wr_bytes == I2C_FMT_FIFO_DEPTH + num_data_ovf;
+  }
+
+  // read transaction length is equal to rx_fifo
+  constraint num_rd_bytes_c { num_rd_bytes == I2C_RX_FIFO_DEPTH; }
+
+  bit check_fifo_full = 1'b1;
+  bit fmt_fifo_full   = 1'b0;
+  bit rx_fifo_full    = 1'b0;
+
+  virtual task body();
+    // hold reading rx_fifo to ensure rx_fifo gets full
+    cfg.en_rx_watermark = 1'b1;
+
+    fork
+      begin
+        while (check_fifo_full) process_fifo_full_status();
+      end
+      begin
+        super.body();
+        check_fifo_full = 1'b0; // gracefully stop process_fifo_full_status
+      end
+    join
+    // verify fmt_fifo and rx_fifo has been in full status
+    `DV_CHECK_EQ({fmt_fifo_full, rx_fifo_full}, 2'b11);
+  endtask : body
+
+  task process_fifo_full_status();
+    bit [TL_DW-1:0] status;
+
+    csr_rd(.ptr(ral.status), .value(status), .backdoor(1'b1));
+    cfg.clk_rst_vif.wait_clks(1);
+    fmt_fifo_full |= bit'(get_field_val(ral.status.fmtfull, status));
+    rx_fifo_full  |= bit'(get_field_val(ral.status.rxfull, status));
+  endtask : process_fifo_full_status
+
+endclass : i2c_fifo_full_vseq
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 49ce25e..db79a8e 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
@@ -18,7 +18,7 @@
     num_rd_bytes == I2C_RX_FIFO_DEPTH + 1;
   }
 
-  task body();
+  virtual task body();
     bit check_fmt_overflow;
     bit check_rx_overflow;
     bit rxempty = 1'b0;
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 843f73f..19c7d7a 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
@@ -25,9 +25,8 @@
   }
   // read transaction length is equal to rx_fifo depth to cross rxilvl
   constraint num_rd_bytes_c { num_rd_bytes == I2C_RX_FIFO_DEPTH; }
-  constraint num_trans_c    { num_trans inside {[8 : 12]}; }
 
-  task body();
+  virtual task body();
     bit check_fmt_watermark, check_rx_watermark;
 
     device_init();
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_override_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_override_vseq.sv
index 07dfdba..65f75c9 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_override_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_override_vseq.sv
@@ -17,6 +17,9 @@
     cfg.m_i2c_agent_cfg.en_monitor = 1'b0;
     cfg.en_scb = 1'b0;
 
+    // disable clear_all_interrupts task due to abnormal assertion of interrupts
+    do_clear_all_interrupts = 1'b0;
+
     device_init();
     host_init();
 
@@ -44,9 +47,4 @@
     end
   endtask : body
 
-  task post_start();
-    super.post_start();
-    `uvm_info(`gfn, "stop simulation", UVM_DEBUG)
-  endtask : post_start
-
 endclass : i2c_override_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
index 507c5f9..2243fc9 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_perf_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_perf_vseq.sv
@@ -3,28 +3,26 @@
 // SPDX-License-Identifier: Apache-2.0
 
 // performance test vseq
-class i2c_perf_vseq extends i2c_rx_tx_vseq;
+class i2c_perf_vseq extends i2c_sanity_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
+      1       :/ 1,
+      [2:8]   :/ 1,
+      [9:32]  :/ 1,
+      256     :/ 1
     };
   }
-  // num_rd_bytes = 1: read transaction length is 256b bytes
+  // num_rd_bytes = 0: 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
+      0       :/ 1,
+      1       :/ 1,
+      [2:8]   :/ 1,
+      [9:32]  :/ 1
     };
   }
   
@@ -51,21 +49,4 @@
     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 f197374..f399a86 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
@@ -69,7 +69,7 @@
   endtask : host_program_target_address
 
   virtual task host_read_trans(bit last_tran);
-    bit  rx_sanity, rx_full, rx_overflow, rx_watermark, start_read;
+    bit rx_sanity, rx_full, rx_overflow, rx_watermark, start_read;
 
     `DV_CHECK_MEMBER_RANDOMIZE_FATAL(num_rd_bytes)
     fork
@@ -107,9 +107,9 @@
         if (cfg.en_rx_overflow) total_rd_bytes--;
         while (!fmt_item.rcont && total_rd_bytes > 0) begin
           csr_rd(.ptr(ral.status.rxfull), .value(rx_full));
-          rx_sanity     = !cfg.en_rx_watermark & !cfg.en_rx_overflow;
-          rx_watermark |= cfg.en_rx_watermark && rx_full;
-          rx_overflow  |= cfg.en_rx_overflow && cfg.intr_vif.pins[RxOverflow];
+          rx_sanity      = !cfg.en_rx_watermark & !cfg.en_rx_overflow;
+          rx_watermark  |= cfg.en_rx_watermark && rx_full;
+          rx_overflow   |= cfg.en_rx_overflow && cfg.intr_vif.pins[RxOverflow];
 
           start_read = rx_sanity    | // sanity test: read rx_fifo asap when there are valid data
                        rx_watermark | // watermark test: read rx_fifo when rx_watermark is triggered
@@ -139,11 +139,16 @@
     end
 
     for (int i = 1; i <= num_wr_bytes; i++) begin
-      `DV_CHECK_RANDOMIZE_WITH_FATAL(fmt_item,
-        start == 1'b0;
-        read  == 1'b0;
-      )
-      fmt_item.fbyte = wr_data[i];
+      // randomize until at least one of format bits is non-zero to ensure
+      // data format will be pushed into fmt_fifo (if not empty)
+      do begin
+        `DV_CHECK_RANDOMIZE_WITH_FATAL(fmt_item,
+          start == 1'b0;
+          read  == 1'b0;
+        )
+        fmt_item.fbyte = wr_data[i];
+      end while (!fmt_item.nakok && !fmt_item.rcont && !fmt_item.fbyte);
+
       // last write byte of last  tran., stop flag must be set to issue stop bit
       // last write byte of other tran., stop is randomly set/unset to issue stop/rstart bit
       fmt_item.stop = (i != num_wr_bytes) ? 1'b0 : ((last_tran) ? 1'b1 : fmt_item.stop);
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 7b02a26..7478e93 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
@@ -10,9 +10,10 @@
   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]}; }
+  // increase num_trans to cover all transaction types
   constraint num_trans_c       { num_trans      inside {[50 : 100]}; }
 
-  task body();
+  virtual task body();
     device_init();
     host_init();
 
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_stretch_timeout_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_stretch_timeout_vseq.sv
new file mode 100644
index 0000000..2699e7e
--- /dev/null
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_stretch_timeout_vseq.sv
@@ -0,0 +1,79 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// basic stretch_timeout test vseq
+class i2c_stretch_timeout_vseq extends i2c_sanity_vseq;
+  `uvm_object_utils(i2c_stretch_timeout_vseq)
+  `uvm_object_new
+
+  // set timeout field to minimum value to ensure
+  // stretch_timeout irq is asserted for every target's ACK
+  constraint t_timeout_c { t_timeout == 1; }
+
+  // timeout is always enabled so stretch_timeout irq is aggressively asserted
+  constraint e_timeout_c { e_timeout == 1; }
+
+  local uint num_wr_st;
+  local uint num_rd_st;
+  local bit  check_wr_st;
+  local bit  check_rd_st;
+
+  virtual task body();
+
+    device_init();
+    host_init();
+
+    for (int i = 0; i < num_trans; i++) begin
+      num_wr_st = 0;
+      num_rd_st = 0;
+      check_wr_st = 1'b0;
+      check_rd_st = 1'b0;
+
+      fork
+        begin
+          check_wr_st = 1'b1;
+          host_send_trans(.num_trans(1), .trans_type(WriteOnly));
+          csr_spinwait(.ptr(ral.status.fmtempty), .exp_data(1'b1));
+          check_wr_st = 1'b0;
+          `uvm_info(`gfn, $sformatf("\ncheck_wr_st %0d", check_wr_st), UVM_DEBUG)
+          // host clock is stretched for every target's ACK thus
+          // num_wr_st must be equal to (num_wr_bytes + 1)
+          // adding 1 is for the target's ACK to the response address byte sent by host
+          `DV_CHECK_EQ(num_wr_st, (num_wr_bytes + 1))
+
+          check_rd_st = 1'b1;
+          host_send_trans(.num_trans(1), .trans_type(ReadOnly));
+          csr_spinwait(.ptr(ral.status.rxempty), .exp_data(1'b1));
+          check_rd_st = 1'b0;
+          `uvm_info(`gfn, $sformatf("\ncheck_rd_st %0d", check_rd_st), UVM_DEBUG)
+          // check_rd_stretch_timeout must be equal to 1
+          // that is the target's ACK to response the address byte sent by host
+          `DV_CHECK_EQ(num_rd_st, 1)
+        end
+        begin
+          while (check_wr_st || check_rd_st) check_wr_st_intr();
+        end
+      join
+    end
+  endtask : body
+
+  task check_wr_st_intr();
+    bit stretch_timeout;
+
+    csr_rd(.ptr(ral.intr_state.stretch_timeout), .value(stretch_timeout));
+    if (stretch_timeout) begin
+      if (check_wr_st) num_wr_st++;
+      if (check_rd_st) num_rd_st++;
+
+      // must wait stretch_timeout event passes (scl_i is deasserted)
+      // before clearing irq otherwise stretch_timeout irq can be re-triggered
+      // within clock pulses that interferes the counters
+      wait(!cfg.m_i2c_agent_cfg.vif.scl_i);
+      clear_interrupt(StretchTimeout);
+      `uvm_info(`gfn, $sformatf("\ncheck_wr_st %0d, check_rd_st %0d",
+          num_wr_st, num_rd_st), UVM_DEBUG)
+    end
+  endtask : check_wr_st_intr
+
+endclass : i2c_stretch_timeout_vseq
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 d09394f..364fdaa 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
@@ -10,4 +10,7 @@
 `include "i2c_override_vseq.sv"
 `include "i2c_fifo_watermark_vseq.sv"
 `include "i2c_fifo_overflow_vseq.sv"
-`include "i2c_perf_vseq.sv"
\ No newline at end of file
+`include "i2c_fifo_full_vseq.sv"
+`include "i2c_perf_vseq.sv"
+`include "i2c_stretch_timeout_vseq.sv"
+
diff --git a/hw/ip/i2c/dv/i2c_sim_cfg.hjson b/hw/ip/i2c/dv/i2c_sim_cfg.hjson
index 95dd64f..2c03779 100644
--- a/hw/ip/i2c/dv/i2c_sim_cfg.hjson
+++ b/hw/ip/i2c/dv/i2c_sim_cfg.hjson
@@ -66,11 +66,20 @@
     }
 
     {
+      name: i2c_fifo_full
+      uvm_test_seq: i2c_fifo_full_vseq
+    }
+
+    {
       name: i2c_perf
-      // define low reseed due to long simulation time
-      reseed: 5
+      reseed: 10
       uvm_test_seq: i2c_perf_vseq
     }
+
+    {
+      name: i2c_stretch_timeout
+      uvm_test_seq: i2c_stretch_timeout_vseq
+    }
   ]
 
   // List of regressions.