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