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