[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.