[i2c,dv] smoke test
Target smoke test
Signed-off-by: Jaedon Kim <jdonjdon@google.com>
diff --git a/hw/dv/sv/i2c_agent/i2c_agent_cfg.sv b/hw/dv/sv/i2c_agent/i2c_agent_cfg.sv
index b193687..8295ce9 100644
--- a/hw/dv/sv/i2c_agent/i2c_agent_cfg.sv
+++ b/hw/dv/sv/i2c_agent/i2c_agent_cfg.sv
@@ -18,8 +18,9 @@
bit host_scl_start;
bit host_scl_stop;
+ event got_stop;
- // this variables can be configured from test
+ // this variables can be configured from host test
uint i2c_host_min_data_rw = 1;
uint i2c_host_max_data_rw = 10;
diff --git a/hw/dv/sv/i2c_agent/i2c_agent_pkg.sv b/hw/dv/sv/i2c_agent/i2c_agent_pkg.sv
index 02934be..cb1ed7d 100644
--- a/hw/dv/sv/i2c_agent/i2c_agent_pkg.sv
+++ b/hw/dv/sv/i2c_agent/i2c_agent_pkg.sv
@@ -17,7 +17,8 @@
// Bus/Transaction types for the agent driver
typedef enum logic [3:0] {
None, DevAck, RdData, WrData,
- HostStart, HostRStart, HostData, HostNAck, HostStop
+ HostStart, HostRStart, HostData, HostAck,
+ HostNAck, HostStop
} drv_type_e;
// register values
diff --git a/hw/dv/sv/i2c_agent/i2c_driver.sv b/hw/dv/sv/i2c_agent/i2c_driver.sv
index 53ae72d..0b0ad90 100644
--- a/hw/dv/sv/i2c_agent/i2c_driver.sv
+++ b/hw/dv/sv/i2c_agent/i2c_driver.sv
@@ -60,7 +60,6 @@
end
endtask : get_and_drive
- // TODO: drive_host_item is WiP
virtual task drive_host_item(i2c_item req);
`uvm_info(`gfn, $sformatf("drv: %s", req.drv_type.name), UVM_MEDIUM)
unique case (req.drv_type)
@@ -76,12 +75,18 @@
for (int i = $bits(req.wdata) -1; i >= 0; i--) begin
cfg.vif.host_data(cfg.timing_cfg, req.wdata[i]);
end
-
- // wait one more cycle for ack
+ // Wait one more cycle for ack
cfg.vif.wait_scl(.iter(1), .tc(cfg.timing_cfg));
end
+ HostAck: begin
+ // Wait for read data and send ack
+ cfg.vif.wait_scl(.iter(8), .tc(cfg.timing_cfg));
+ cfg.vif.host_data(cfg.timing_cfg, 0);
+ end
HostNAck: begin
- cfg.vif.host_nack(cfg.timing_cfg);
+ // Wait for read data and send nack
+ cfg.vif.wait_scl(.iter(8), .tc(cfg.timing_cfg));
+ cfg.vif.host_data(cfg.timing_cfg, 1);
end
HostStop: begin
cfg.host_scl_stop = 1;
@@ -152,14 +157,16 @@
endtask : release_bus
task drive_scl();
+ int scl_spinwait_timeout_ns = 1_000_000; // 1ms
forever begin
+ @(cfg.vif.cb);
wait(cfg.host_scl_start);
while(!cfg.host_scl_stop) begin
- cfg.vif.scl_o = 1'b0;
+ cfg.vif.scl_o <= 1'b0;
cfg.vif.wait_for_dly(cfg.timing_cfg.tClockLow);
cfg.vif.wait_for_dly(cfg.timing_cfg.tSetupBit);
- cfg.vif.scl_o = 1'b1;
- wait(cfg.vif.cb.scl_i === 1'b1);
+ cfg.vif.scl_o <= 1'b1;
+ `DV_WAIT(cfg.vif.scl_i === 1'b1,, scl_spinwait_timeout_ns, "i2c_drv_scl")
cfg.vif.wait_for_dly(cfg.timing_cfg.tClockPulse);
if (!cfg.host_scl_stop) cfg.vif.scl_o = 1'b0;
cfg.vif.wait_for_dly(cfg.timing_cfg.tHoldBit);
diff --git a/hw/dv/sv/i2c_agent/i2c_if.sv b/hw/dv/sv/i2c_agent/i2c_if.sv
index 53de546..a828139 100644
--- a/hw/dv/sv/i2c_agent/i2c_if.sv
+++ b/hw/dv/sv/i2c_agent/i2c_if.sv
@@ -27,10 +27,22 @@
clocking cb @(posedge clk_i);
input scl_i;
+ input sda_i;
+ output scl_o;
+ output sda_o;
endclocking
//---------------------------------
// common tasks
//---------------------------------
+
+ // This is literally same as '@(posedge scl_i)'
+ // In target mode, @(posedge scl_i) gives some glitch,
+ // so I have to use clocking block sampled signals.
+ task automatic p_edge_scl();
+ wait(cb.scl_i == 0);
+ wait(cb.scl_i == 1);
+ endtask
+
task automatic wait_for_dly(int dly);
repeat (dly) @(posedge clk_i);
endtask : wait_for_dly
@@ -218,7 +230,7 @@
@(negedge scl_i);
wait_for_dly(tc.tHoldBit - tc.tSdaInterference);
end else begin // target transmits data (rd_data)
- bit_o = sda_o;
+ bit_o = sda_i;
wait_for_dly(tc.tClockPulse + tc.tHoldBit);
end
endtask: get_bit_data
@@ -231,52 +243,48 @@
endtask: host_start
task automatic host_rstart(ref timing_cfg_t tc);
- scl_o = 1'b0;
- wait_for_dly(tc.tSetupStart);
- sda_o = 1'b0;
- scl_o = 1'b1;
- wait_for_dly(tc.tHoldStart);
- scl_o = 1'b0;
- wait_for_dly(tc.tClockStart);
+ wait(scl_i === 1'b1);
+ wait_for_dly(tc.tSetupStart);
+ sda_o = 1'b0;
+ wait_for_dly(tc.tHoldStart);
+ wait_for_dly(tc.tHoldBit);
endtask: host_rstart
task automatic host_data(ref timing_cfg_t tc, input bit bit_i);
sda_o = bit_i;
wait_for_dly(tc.tClockLow);
wait_for_dly(tc.tSetupBit);
- wait(cb.scl_i === 1'b1);
+ wait(scl_i === 1'b1);
wait_for_dly(tc.tClockPulse);
wait_for_dly(tc.tHoldBit);
+ sda_o = 1;
endtask: host_data
task automatic host_stop(ref timing_cfg_t tc);
- sda_o = 1'b0;
- wait_for_dly(tc.tClockStop);
- scl_o = 1'b1;
- wait_for_dly(tc.tSetupStop);
- sda_o = 1'b0;
- wait_for_dly(tc.tHoldStop);
+ sda_o = 1'b0;
+ wait_for_dly(tc.tClockStop);
+ scl_o = 1'b1;
+ wait_for_dly(tc.tSetupStop);
+ sda_o = 1'b0;
+ wait_for_dly(tc.tHoldStop);
endtask: host_stop
task automatic host_nack(ref timing_cfg_t tc);
- sda_o = 1'b0;
- wait_for_dly(tc.tClockLow);
- sda_o = 1'b1;
- wait_for_dly(tc.tSetupBit);
- scl_o = 1'b1;
- wait_for_dly(tc.tClockPulse);
- scl_o = 1'b0;
- wait_for_dly(tc.tHoldBit);
+ sda_o = 1'b0;
+ wait_for_dly(tc.tClockLow);
+ sda_o = 1'b1;
+ wait_for_dly(tc.tSetupBit);
+ scl_o = 1'b1;
+ wait_for_dly(tc.tClockPulse);
+ scl_o = 1'b0;
+ wait_for_dly(tc.tHoldBit);
endtask: host_nack
task automatic wait_scl(int iter = 1, timing_cfg_t tc);
repeat(iter) begin
- wait_for_dly(tc.tClockLow);
- wait_for_dly(tc.tSetupBit);
- wait(cb.scl_i === 1'b1);
- wait_for_dly(tc.tClockPulse);
- wait_for_dly(tc.tHoldBit);
+ wait_for_dly(tc.tClockLow + tc.tSetupBit);
+ wait(scl_i === 1'b1);
+ wait_for_dly(tc.tClockPulse + tc.tHoldBit);
end
endtask // wait_scl
-
endinterface : i2c_if
diff --git a/hw/dv/sv/i2c_agent/i2c_item.sv b/hw/dv/sv/i2c_agent/i2c_item.sv
index 34089fd..ba0fd9d 100644
--- a/hw/dv/sv/i2c_agent/i2c_item.sv
+++ b/hw/dv/sv/i2c_agent/i2c_item.sv
@@ -27,6 +27,9 @@
logic [7:0] wdata;
logic [7:0] rdata;
+ // Use for debug print
+ string pname = "";
+
constraint fbyte_c { fbyte inside {[0 : 127] }; }
constraint rcont_c {
solve read, stop before rcont;
@@ -46,15 +49,15 @@
`uvm_field_int(start, UVM_DEFAULT)
`uvm_field_int(stop, UVM_DEFAULT)
`uvm_field_int(wdata, UVM_DEFAULT | UVM_NOCOMPARE)
- `uvm_field_queue_int(data_q, UVM_DEFAULT)
+ `uvm_field_queue_int(data_q, UVM_DEFAULT | UVM_NOPRINT)
`uvm_field_queue_int(fmt_ovf_data_q, UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_field_int(rdata, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
- `uvm_field_int(rstart, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
+ `uvm_field_int(rstart, UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_field_int(fbyte, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
`uvm_field_int(ack, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
`uvm_field_int(nack, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
- `uvm_field_int(read, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
- `uvm_field_int(rcont, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
+ `uvm_field_int(read, UVM_DEFAULT | UVM_NOCOMPARE)
+ `uvm_field_int(rcont, UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_field_int(nakok, UVM_DEFAULT | UVM_NOPRINT | UVM_NOCOMPARE)
`uvm_field_enum(drv_type_e, drv_type, UVM_DEFAULT | UVM_NOCOMPARE)
`uvm_object_utils_end
@@ -85,4 +88,19 @@
clear_flag();
endfunction : clear_all
+ virtual function string convert2string();
+ string str = "";
+ str = {str, $sformatf("%s:tran_id = %0d\n", pname, tran_id)};
+ str = {str, $sformatf("%s:bus_op = %s\n", pname, bus_op.name)};
+ str = {str, $sformatf("%s:addr = 0x%2x\n", pname, addr)};
+ str = {str, $sformatf("%s:num_data = %0d\n", pname, num_data)};
+ str = {str, $sformatf("%s:start = %1b\n", pname, start)};
+ str = {str, $sformatf("%s:stop = %1b\n", pname, stop)};
+ str = {str, $sformatf("%s:read = %1b\n", pname, read)};
+ str = {str, $sformatf("%s:rstart = %1b\n", pname, rstart)};
+ foreach (data_q[i]) begin
+ str = {str, $sformatf("%s:data_q[%0d]=0x%2x\n", pname, i, data_q[i])};
+ end
+ return str;
+ endfunction
endclass : i2c_item
diff --git a/hw/dv/sv/i2c_agent/i2c_monitor.sv b/hw/dv/sv/i2c_agent/i2c_monitor.sv
index a9f9c22..0de583d 100644
--- a/hw/dv/sv/i2c_agent/i2c_monitor.sv
+++ b/hw/dv/sv/i2c_agent/i2c_monitor.sv
@@ -34,26 +34,72 @@
virtual task run_phase(uvm_phase phase);
wait(cfg.vif.rst_ni);
- forever begin
- fork
- begin: iso_fork
- fork
- begin
- collect_thread(phase);
- end
- begin // if (on-the-fly) reset is monitored, drop the item
- wait_for_reset_and_drop_item();
- `uvm_info(`gfn, $sformatf("\nmonitor is reset, drop item\n%s",
- mon_dut_item.sprint()), UVM_DEBUG)
- end
- join_any
- disable fork;
- end: iso_fork
- join
+ if (cfg.if_mode == Host) begin
+ bit r_bit = 1'b0;
+ i2c_item full_item;
+ forever begin
+ if (mon_dut_item.stop ||
+ (!mon_dut_item.stop && !mon_dut_item.start && !mon_dut_item.rstart)) begin
+ cfg.vif.wait_for_host_start(cfg.timing_cfg);
+ `uvm_info(`gfn, "\nmonitor, detect HOST START", UVM_MEDIUM)
+ end else begin
+ mon_dut_item.rstart = 1'b1;
+ end
+ num_dut_tran++;
+ mon_dut_item.start = 1'b1;
+ // collecting address
+ for (int i = cfg.target_addr_mode - 1; i >= 0; i--) begin
+ cfg.vif.p_edge_scl();
+ mon_dut_item.addr[i] = cfg.vif.cb.sda_i;
+ `uvm_info(`gfn, $sformatf("\nmonitor, address[%0d] %b", i, mon_dut_item.addr[i]),
+ UVM_HIGH)
+ end
+ `uvm_info(`gfn, $sformatf("\nmonitor, address %0x", mon_dut_item.addr), UVM_MEDIUM)
+ cfg.vif.p_edge_scl();
+ r_bit = cfg.vif.cb.sda_i;
+ `uvm_info(`gfn, $sformatf("\nmonitor, rw %d", r_bit), UVM_MEDIUM)
+ mon_dut_item.bus_op = (r_bit) ? BusOpRead : BusOpWrite;
+
+ // expect target ack
+ cfg.vif.p_edge_scl();
+ r_bit = cfg.vif.cb.sda_i;
+ `DV_CHECK_CASE_EQ(r_bit, 1'b0)
+
+ if (mon_dut_item.bus_op == BusOpRead)
+ target_read();
+ else target_write();
+
+ // send rsp_item to scoreboard
+ `downcast(full_item, mon_dut_item.clone());
+ full_item.stop = 1'b1;
+ if (mon_dut_item.bus_op == BusOpRead) begin
+ full_item.read = 1;
+ analysis_port.write(full_item);
+ end
+ mon_dut_item.clear_data();
+ end
+ end else begin
+ forever begin
+ fork
+ begin: iso_fork
+ fork
+ begin
+ collect_thread(phase);
+ end
+ begin // if (on-the-fly) reset is monitored, drop the item
+ wait_for_reset_and_drop_item();
+ `uvm_info(`gfn, $sformatf("\nmonitor is reset, drop item\n%s",
+ mon_dut_item.sprint()), UVM_DEBUG)
+ end
+ join_any
+ disable fork;
+ end: iso_fork
+ join
+ end
end
endtask : run_phase
- // collect transactions forever
+ // Collect transactions forever
virtual protected task collect_thread(uvm_phase phase);
i2c_item full_item;
wait(cfg.en_monitor);
@@ -196,8 +242,76 @@
virtual task monitor_ready_to_end();
forever begin
@(cfg.vif.scl_i or cfg.vif.sda_i or cfg.vif.scl_o or cfg.vif.sda_o);
- ok_to_end = (cfg.vif.scl_i == 1'b1) && (cfg.vif.sda_i == 1'b1);
+ if (cfg.if_mode == Host) begin
+ // TODO: set end condition if necessary
+ end else begin
+ ok_to_end = (cfg.vif.scl_i == 1'b1) && (cfg.vif.sda_i == 1'b1);
+ end
end
endtask : monitor_ready_to_end
+ // Rewrite read / write task using glitch free edge functions.
+ task target_read();
+ mon_dut_item.stop = 1'b0;
+ mon_dut_item.rstart = 1'b0;
+ mon_dut_item.ack = 1'b0;
+ mon_dut_item.nack = 1'b0;
+
+ while (!mon_dut_item.stop && !mon_dut_item.rstart) begin
+ // ask driver response read data
+ mon_dut_item.drv_type = RdData;
+ for (int i = 7; i >= 0; i--) begin
+ cfg.vif.p_edge_scl();
+ mon_data[i] = cfg.vif.cb.sda_i;
+ `uvm_info(`gfn, $sformatf("\nmonitor, target_read, trans %0d, byte %0d, bit[%0d] %0b",
+ mon_dut_item.tran_id, mon_dut_item.num_data+1, i, mon_data[i]), UVM_HIGH)
+ end
+ mon_dut_item.data_q.push_back(mon_data);
+ mon_dut_item.num_data++;
+ `uvm_info(`gfn, $sformatf("\nmonitor, target_read, trans %0d, byte %0d 0x%0x",
+ mon_dut_item.tran_id, mon_dut_item.num_data, mon_data), UVM_MEDIUM)
+ cfg.vif.wait_for_host_ack_or_nack(cfg.timing_cfg, mon_dut_item.ack, mon_dut_item.nack);
+ `DV_CHECK_NE_FATAL({mon_dut_item.ack, mon_dut_item.nack}, 2'b11)
+ `uvm_info(`gfn, $sformatf("\nmonitor, target_read detect HOST %s",
+ (mon_dut_item.ack) ? "ACK" : "NO_ACK"), UVM_MEDIUM)
+ // if nack is issued, next bit must be stop or rstart
+ if (mon_dut_item.nack) begin
+ cfg.vif.wait_for_host_stop_or_rstart(cfg.timing_cfg,
+ mon_dut_item.rstart,
+ mon_dut_item.stop);
+ `DV_CHECK_NE_FATAL({mon_dut_item.rstart, mon_dut_item.stop}, 2'b11)
+ `uvm_info(`gfn, $sformatf("\nmonitor, target_read, detect HOST %s",
+ (mon_dut_item.stop) ? "STOP" : "RSTART"), UVM_MEDIUM)
+ if (mon_dut_item.stop) ->cfg.got_stop;
+ end
+ end
+ endtask
+
+ task target_write();
+ bit r_bit;
+ mon_dut_item.stop = 1'b0;
+ mon_dut_item.rstart = 1'b0;
+ while (!mon_dut_item.stop && !mon_dut_item.rstart) begin
+ mon_dut_item.drv_type = WrData;
+ for (int i = 7; i >= 0; i--) begin
+ cfg.vif.p_edge_scl();
+ end
+ // check for ack
+ cfg.vif.p_edge_scl();
+ r_bit = cfg.vif.cb.sda_i;
+ `uvm_info(`gfn, $sformatf("\nmonitor, target_write detect HOST %s",
+ (!r_bit) ? "ACK" : "NO_ACK"), UVM_MEDIUM)
+ // if nack is issued, next bit must be stop or rstart
+ if (!r_bit) begin
+ cfg.vif.wait_for_host_stop_or_rstart(cfg.timing_cfg,
+ mon_dut_item.rstart,
+ mon_dut_item.stop);
+ `DV_CHECK_NE_FATAL({mon_dut_item.rstart, mon_dut_item.stop}, 2'b11)
+ `uvm_info(`gfn, $sformatf("\nmonitor, rd_data, detect HOST %s",
+ (mon_dut_item.stop) ? "STOP" : "RSTART"), UVM_MEDIUM)
+ if (mon_dut_item.stop) ->cfg.got_stop;
+ end
+ end
+ endtask // target_write
+
endclass : i2c_monitor
diff --git a/hw/ip/i2c/data/i2c_testplan.hjson b/hw/ip/i2c/data/i2c_testplan.hjson
index aa262c2..d9fae51 100644
--- a/hw/ip/i2c/data/i2c_testplan.hjson
+++ b/hw/ip/i2c/data/i2c_testplan.hjson
@@ -252,7 +252,7 @@
- Read and write transfer matching
'''
stage: V1
- tests: [""]
+ tests: ["i2c_target_smoke"]
}
{
name: target_error_intr
diff --git a/hw/ip/i2c/dv/env/i2c_env.sv b/hw/ip/i2c/dv/env/i2c_env.sv
index e0ec79e..be1ad72 100644
--- a/hw/ip/i2c/dv/env/i2c_env.sv
+++ b/hw/ip/i2c/dv/env/i2c_env.sv
@@ -32,6 +32,11 @@
if (cfg.m_i2c_agent_cfg.if_mode == Host) begin
virtual_sequencer.target_mode_wr_exp_port.connect(
scoreboard.target_mode_wr_exp_fifo.analysis_export);
+ virtual_sequencer.target_mode_wr_obs_port.connect(
+ scoreboard.target_mode_wr_obs_fifo.analysis_export);
+ m_i2c_agent.monitor.analysis_port.connect(scoreboard.target_mode_rd_obs_fifo.analysis_export);
+ virtual_sequencer.target_mode_rd_exp_port.connect(
+ scoreboard.target_mode_rd_exp_fifo.analysis_export);
end
endfunction
diff --git a/hw/ip/i2c/dv/env/i2c_env_cfg.sv b/hw/ip/i2c/dv/env/i2c_env_cfg.sv
index 01baba5..56204bc 100644
--- a/hw/ip/i2c/dv/env/i2c_env_cfg.sv
+++ b/hw/ip/i2c/dv/env/i2c_env_cfg.sv
@@ -16,6 +16,20 @@
tran_type_e trans_type = ReadWrite;
+ int sent_acq_cnt;
+ int rcvd_acq_cnt;
+
+ // Ratio between write and read
+ int wr_pct = 1;
+ int rd_pct = 1;
+
+ // re-start injection rate between 1~10
+ int rs_pct = 1;
+
+ // dut target mode parameters
+ int min_data = 1;
+ int max_data = 60;
+
`uvm_object_utils_begin(i2c_env_cfg)
`uvm_field_object(m_i2c_agent_cfg, UVM_DEFAULT)
`uvm_object_utils_end
diff --git a/hw/ip/i2c/dv/env/i2c_env_pkg.sv b/hw/ip/i2c/dv/env/i2c_env_pkg.sv
index 71a9513..d75f937 100644
--- a/hw/ip/i2c/dv/env/i2c_env_pkg.sv
+++ b/hw/ip/i2c/dv/env/i2c_env_pkg.sv
@@ -61,11 +61,14 @@
item.wdata = data[7:0];
if (data[9:8] == 2'b11) begin
- // TODO Re start support
+ item.rstart = 1;
end else begin
item.start = data[8];
item.stop = data[9];
end
+ if (item.start || item.rcont) begin
+ item.read = data[0];
+ end
return item;
endfunction // acq2item
diff --git a/hw/ip/i2c/dv/env/i2c_scoreboard.sv b/hw/ip/i2c/dv/env/i2c_scoreboard.sv
index 374c1ad..0cbe681 100644
--- a/hw/ip/i2c/dv/env/i2c_scoreboard.sv
+++ b/hw/ip/i2c/dv/env/i2c_scoreboard.sv
@@ -13,6 +13,8 @@
local i2c_item exp_rd_item;
local i2c_item exp_wr_item;
+ local i2c_item obs_wr_item;
+ local i2c_item obs_rd_item;
local i2c_item rd_pending_item;
local uint rd_wait;
local bit host_init = 1'b0;
@@ -33,10 +35,16 @@
// Target mode transactions
uvm_tlm_analysis_fifo #(i2c_item) target_mode_wr_exp_fifo;
+ uvm_tlm_analysis_fifo #(i2c_item) target_mode_wr_obs_fifo;
+ uvm_tlm_analysis_fifo #(i2c_item) target_mode_rd_exp_fifo;
+ uvm_tlm_analysis_fifo #(i2c_item) target_mode_rd_obs_fifo;
// interrupt bit vector
local bit [NumI2cIntr-1:0] intr_exp;
+ int num_obs_rd;
+
+
`uvm_component_new
function void build_phase(uvm_phase phase);
@@ -46,20 +54,38 @@
rd_pending_item = new("rd_pending_item" );
exp_rd_item = new("exp_rd_item");
exp_wr_item = new("exp_wr_item");
+ obs_wr_item = new("obs_wr_item");
target_mode_wr_exp_fifo = new("target_mode_wr_exp_fifo", this);
+ target_mode_wr_obs_fifo = new("target_mode_wr_obs_fifo", this);
+ target_mode_rd_exp_fifo = new("target_mode_rd_exp_fifo", this);
+ target_mode_rd_obs_fifo = new("target_mode_rd_obs_fifo", this);
endfunction : build_phase
task run_phase(uvm_phase phase);
+ string str;
super.run_phase(phase);
if (cfg.m_i2c_agent_cfg.if_mode == Host) begin
- fork begin
+ int obs_wr_id = 0;
+ fork
forever begin
target_mode_wr_exp_fifo.get(exp_wr_item);
- `uvm_info(`gfn, $sformatf("exp_tn%0d\n %s",
+ str = (exp_wr_item.start) ? "addr" : (exp_wr_item.stop) ? "stop" : "wr";
+ `uvm_info(`gfn, $sformatf("exp_%s_txn%0d\n %s", str,
exp_wr_item.tran_id, exp_wr_item.sprint()), UVM_MEDIUM)
- process_target_write(exp_wr_item);
+ target_mode_wr_obs_fifo.get(obs_wr_item);
+ obs_wr_item.tran_id = obs_wr_id++;
+ target_txn_comp(obs_wr_item, exp_wr_item, str);
end
- end join_none
+ forever begin
+ target_mode_rd_exp_fifo.get(exp_rd_item);
+ exp_rd_item.pname = "exp_rd";
+ `uvm_info(`gfn, $sformatf("\n%s", exp_rd_item.convert2string()), UVM_MEDIUM)
+ target_mode_rd_obs_fifo.get(obs_rd_item);
+ obs_rd_item.pname = "obs_rd";
+ obs_rd_item.tran_id = num_obs_rd++;
+ target_rd_comp(obs_rd_item, exp_rd_item);
+ end
+ join_none
end else begin
forever begin
`DV_SPINWAIT_EXIT(
@@ -409,31 +435,27 @@
`DV_EOT_PRINT_TLM_FIFO_CONTENTS(i2c_item, wr_item_fifo)
endfunction
- task process_target_write(i2c_item exp);
- uvm_reg_data_t read_data;
- i2c_item obs;
-
- // polling status.acqempty == 0
- csr_spinwait(.ptr(ral.status.acqempty), .exp_data(1'b0),
- .timeout_ns(10_000));
-
- // read one entry and compare
- csr_rd(.ptr(ral.acqdata), .value(read_data));
- `uvm_create_obj(i2c_item, obs);
- obs = acq2item(read_data);
- obs.tran_id = this.tran_id++;
- target_txn_comp(obs, exp);
-
- endtask // process_target_write
-
// Compare start, stop and wdata only
- function void target_txn_comp(i2c_item obs, i2c_item exp);
- `uvm_info(`gfn, $sformatf("comp:target wr_txn %0d", obs.tran_id), UVM_MEDIUM)
+ function void target_txn_comp(i2c_item obs, i2c_item exp, string str);
+ `uvm_info(`gfn, $sformatf("comp:target obs_%s_txn %0d\n%s", str, obs.tran_id, obs.sprint()),
+ UVM_MEDIUM)
+
+ `DV_CHECK_EQ(obs.tran_id, exp.tran_id)
`DV_CHECK_EQ(obs.start, exp.start)
`DV_CHECK_EQ(obs.stop, exp.stop)
- if (obs.stop == 0) begin
+ if (obs.stop == 0 && obs.rstart == 0) begin
`DV_CHECK_EQ(obs.wdata, exp.wdata)
end
endfunction // target_txn_comp
+ function void target_rd_comp(i2c_item obs, i2c_item exp);
+ `uvm_info(`gfn, $sformatf("comp:target obs_rd %0d\n%s", obs.tran_id, obs.convert2string()),
+ UVM_MEDIUM)
+ `DV_CHECK_EQ(obs.tran_id, exp.tran_id)
+ `DV_CHECK_EQ(obs.num_data, exp.num_data)
+ `DV_CHECK_EQ(obs.data_q.size(), exp.data_q.size())
+ foreach (exp.data_q[i]) begin
+ `DV_CHECK_EQ(obs.data_q[i], exp.data_q[i])
+ end
+ endfunction // target_rd_comp
endclass : i2c_scoreboard
diff --git a/hw/ip/i2c/dv/env/i2c_seq_cfg.sv b/hw/ip/i2c/dv/env/i2c_seq_cfg.sv
index f150fe6..1355b45 100644
--- a/hw/ip/i2c/dv/env/i2c_seq_cfg.sv
+++ b/hw/ip/i2c/dv/env/i2c_seq_cfg.sv
@@ -53,10 +53,6 @@
// set en_sda_interference to allow sda_interference irq is triggered
bit en_sda_interference = 1'b0;
- // dut target mode parameters
- int min_data = 1;
- int max_data = 1;
-
`uvm_object_new
endclass : i2c_seq_cfg
diff --git a/hw/ip/i2c/dv/env/i2c_virtual_sequencer.sv b/hw/ip/i2c/dv/env/i2c_virtual_sequencer.sv
index 2084454..f3e4939 100644
--- a/hw/ip/i2c/dv/env/i2c_virtual_sequencer.sv
+++ b/hw/ip/i2c/dv/env/i2c_virtual_sequencer.sv
@@ -6,6 +6,8 @@
.COV_T(i2c_env_cov));
i2c_sequencer i2c_sequencer_h;
uvm_analysis_port #(i2c_item) target_mode_wr_exp_port;
+ uvm_analysis_port #(i2c_item) target_mode_wr_obs_port;
+ uvm_analysis_port #(i2c_item) target_mode_rd_exp_port;
`uvm_component_utils(i2c_virtual_sequencer)
`uvm_component_new
@@ -13,5 +15,7 @@
function void build_phase(uvm_phase phase);
super.build_phase(phase);
target_mode_wr_exp_port = new("target_mode_wr_exp_port", this);
+ target_mode_wr_obs_port = new("target_mode_wr_obs_port", this);
+ target_mode_rd_exp_port = new("target_mode_rd_exp_port", this);
endfunction
endclass : i2c_virtual_sequencer
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 597442f..3638de6 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
@@ -58,7 +58,16 @@
rand uint prob_scl_interference;
// host timeout ctrl value
- bit [31:0] host_timeout_ctrl = 32'hffff;
+ bit [31:0] host_timeout_ctrl = 32'hffff;
+ // Start counter including restart. Starting from 1 to match rtl value
+ // and easy to trace.
+ int start_cnt = 1;
+ int read_rcvd[$];
+ int full_txn_num = 0;
+ int exp_rd_id = 0;
+ int exp_wr_id = 0;
+ i2c_item read_txn_q[$];
+ int tran_id = 0;
// constraints
constraint addr_c {
@@ -250,9 +259,9 @@
csr_update(ral.ctrl);
// TODO: more initialization for the host running Target mode
ral.target_id.address0.set(target_addr0);
- ral.target_id.mask0.set(7'h3f);
+ ral.target_id.mask0.set(7'h7f);
ral.target_id.address1.set(target_addr1);
- ral.target_id.mask1.set(7'h3f);
+ ral.target_id.mask1.set(7'h7f);
csr_update(ral.target_id);
// Host timeout control
ral.host_timeout_ctrl.set(this.host_timeout_ctrl);
@@ -518,4 +527,298 @@
csr_wr(.ptr(ral.stretch_ctrl.en_addr_acq), .value(en_addr_acq));
csr_wr(.ptr(ral.stretch_ctrl.en_addr_tx), .value(en_addr_tx));
endtask : program_stretch_ctrl
+
+ // Use for debug only
+ function void print_time_property();
+ `uvm_info(`gfn, $sformatf("timing_prop"), UVM_MEDIUM)
+ // high period of the SCL in clock units
+ `uvm_info(`gfn, $sformatf("thigh:%0d", thigh), UVM_MEDIUM);
+ // low period of the SCL in clock units
+ `uvm_info(`gfn, $sformatf("tlow:%0d", tlow), UVM_MEDIUM);
+ // rise time of both SDA and SCL in clock units
+ `uvm_info(`gfn, $sformatf("t_r:%0d", t_r), UVM_MEDIUM);
+ // fall time of both SDA and SCL in clock units
+ `uvm_info(`gfn, $sformatf("t_f:%0d", t_f), UVM_MEDIUM);
+ // hold time for (repeated) START in clock units
+ `uvm_info(`gfn, $sformatf("thd_sta:%0d", thd_sta), UVM_MEDIUM);
+ // setup time for repeated START in clock units
+ `uvm_info(`gfn, $sformatf("tsu_sta:%0d", tsu_sta), UVM_MEDIUM);
+ // setup time for STOP in clock units
+ `uvm_info(`gfn, $sformatf("tsu_sto:%0d", tsu_sto), UVM_MEDIUM);
+ // data setup time in clock units
+ `uvm_info(`gfn, $sformatf("tsu_dat:%0d", tsu_dat), UVM_MEDIUM);
+ // data hold time in clock units
+ `uvm_info(`gfn, $sformatf("thd_dat:%0d", thd_dat), UVM_MEDIUM);
+ // bus free time between STOP and START in clock units
+ `uvm_info(`gfn, $sformatf("t_buf:%0d", t_buf), UVM_MEDIUM);
+ // max time target may stretch the clock
+ `uvm_info(`gfn, $sformatf("t_timeout:%0d", t_timeout), UVM_MEDIUM);
+ // max time target may stretch the clock
+ `uvm_info(`gfn, $sformatf("e_timeout:%0d", e_timeout), UVM_MEDIUM);
+ // sda unstable time during the posedge_clock
+ `uvm_info(`gfn, $sformatf("t_sda_unstable:%0d", t_sda_unstable), UVM_MEDIUM);
+ // sda interference time during the posedge_clock
+ `uvm_info(`gfn, $sformatf("t_sda_interference:%0d", t_sda_interference), UVM_MEDIUM);
+ // scl interference time during the posedge_clock
+ `uvm_info(`gfn, $sformatf("t_scl_interference:%0d", t_scl_interference), UVM_MEDIUM);
+ `uvm_info(`gfn, $sformatf("error intrs probability"), UVM_MEDIUM)
+ `uvm_info(`gfn, $sformatf("prob_sda_unstable:%0d ", prob_sda_unstable), UVM_MEDIUM);
+ `uvm_info(`gfn, $sformatf("prob_sda_interference:%0d", prob_sda_interference), UVM_MEDIUM);
+ `uvm_info(`gfn, $sformatf("prob_scl_interference:%0d", prob_scl_interference), UVM_MEDIUM);
+ endfunction
+
+ // Print i2c_item.data_q with RS command notation
+ function void print_wr_data(i2c_item myq[$]);
+ int idx = 1;
+ `uvm_info("seq", $sformatf("q size:%0d", myq.size()), UVM_MEDIUM)
+ foreach (myq[i]) begin
+ if (myq[i].rstart) begin
+ `uvm_info("seq", $sformatf("idx %0d RS rw:%0d", start_cnt++, myq[i].read), UVM_MEDIUM)
+ idx = 1;
+ end else begin
+ `uvm_info("seq", $sformatf("%2d: 0x%2x", idx++, myq[i].wdata), UVM_MEDIUM)
+ end
+ end
+ endfunction
+
+ // set rw bit based on cfg rd/wr pct
+ function bit get_read_write();
+ bit rw;
+ randcase
+ cfg.wr_pct: rw = 0;
+ cfg.rd_pct: rw = 1;
+ endcase
+ return rw;
+ endfunction // get_read_write
+
+ // Read acqdata and pass to scoreboard until
+ // send and rcv cnt become the same.
+ virtual task process_acq();
+ uvm_reg_data_t read_data;
+ i2c_item obs;
+ bit is_read;
+
+ wait(cfg.sent_acq_cnt > 0);
+
+ while (cfg.sent_acq_cnt != cfg.rcvd_acq_cnt) begin
+ // polling status.acqempty == 0
+ csr_rd(.ptr(ral.status.acqempty), .value(read_data));
+ if (read_data == 0) begin
+
+ // read one entry and compare
+ csr_rd(.ptr(ral.acqdata), .value(read_data));
+ `uvm_info("process_acq", $sformatf("acq data %x", read_data), UVM_MEDIUM)
+ `uvm_create_obj(i2c_item, obs);
+ obs = acq2item(read_data);
+ is_read = obs.read;
+
+ obs.tran_id = cfg.rcvd_acq_cnt++;
+ p_sequencer.target_mode_wr_obs_port.write(obs);
+ end else begin // if (read_data == 0)
+ cfg.clk_rst_vif.wait_clks(1);
+ `uvm_info("process_acq", $sformatf("acq_dbg: sent:%0d rcvd:%0d acq_is_empty",
+ cfg.sent_acq_cnt, cfg.rcvd_acq_cnt), UVM_HIGH)
+ end
+ end
+ endtask
+
+ // Polling read_rcvd q and fetch read data to txdata fifo
+ virtual task process_txq();
+ uvm_reg_data_t data;
+ int read_size;
+ int rd_txfifo_timeout_ns = 50_000;
+
+ forever begin
+ @(cfg.m_i2c_agent_cfg.vif.cb);
+ if (read_rcvd.size() > 0) begin
+ read_size = read_rcvd.pop_front();
+ end
+ while (read_size > 0) begin
+ @(cfg.m_i2c_agent_cfg.vif.cb);
+ if (read_txn_q.size() > 0) begin
+ i2c_item item;
+ //check tx fifo is full
+ csr_spinwait(.ptr(ral.status.txfull), .exp_data(1'b0),
+ .timeout_ns(rd_txfifo_timeout_ns));
+ `uvm_create_obj(i2c_item, item)
+ item = read_txn_q.pop_front();
+ `uvm_info("process_txq", $sformatf("send rdata:%x", item.wdata), UVM_MEDIUM)
+ csr_wr(.ptr(ral.txdata), .value(item.wdata));
+ read_size--;
+ end
+ end
+ end
+ endtask
+
+ // Create byte transaction (payload) to read or write.
+ // Restart can be stuffed in between bytes except first and the last bytes.
+ // While normal transaction type (read, write) is decided in 'fetch_txn',
+ // Restat transaction type is set here to make io trace easier.
+ virtual function void create_txn(ref i2c_item myq[$]);
+ bit [7:0] wdata_q[$];
+ i2c_item txn;
+ bit rs_avl;
+
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(wdata_q,
+ wdata_q.size() inside {
+ [cfg.min_data : cfg.max_data]};)
+
+ for (int i = 0; i < wdata_q.size(); i++) begin
+ if ($urandom_range(0,9) < cfg.rs_pct) rs_avl = 1;
+ else rs_avl = 0;
+ // restart entry
+ if (rs_avl == 1 && wdata_q.size() > 1 &&
+ i inside {[1:wdata_q.size() -1]}) begin
+ `uvm_info("seq", $sformatf("RS inserted before data %0d", i), UVM_MEDIUM)
+ `uvm_create_obj(i2c_item, txn)
+ txn.drv_type = HostRStart;
+ txn.rstart = 1;
+ txn.stop = 0;
+ txn.read = get_read_write();
+ myq.push_back(txn);
+ end
+ `uvm_create_obj(i2c_item, txn)
+ txn.drv_type = HostData;
+ txn.wdata = wdata_q[i];
+ myq.push_back(txn);
+ end
+ endfunction
+
+ // Receive byte stream from 'create_txn' and forward to driver's request q,
+ // with adding 'Start and Stop'.
+ // Expected transaction is created in the task.
+ // For write transaction and address transaction, expected transaction mimics acq read data.
+ // For read transaction, all read bytes for one transaction is accumulated to 'full_txn'
+ // and compared with received transaction at the scoreboard.
+ // TODO : target address will be randomly picked between target_addr0 nad target_addr1.
+ virtual function void fetch_txn(ref i2c_item src_q[$], i2c_item dst_q[$]);
+ i2c_item txn;
+ i2c_item rs_txn;
+ i2c_item exp_txn;
+ i2c_item full_txn;
+ int read_size;
+ bit is_read = get_read_write();
+
+ `uvm_info("seq", $sformatf("idx %0d:is_read:%0b size:%0d fetch_txn:%0d", start_cnt++, is_read,
+ src_q.size(), full_txn_num++), UVM_MEDIUM)
+ print_wr_data(src_q);
+ `uvm_create_obj(i2c_item, full_txn)
+
+ // Add 'START' to the front
+ `uvm_create_obj(i2c_item, txn)
+ txn.drv_type = HostStart;
+ dst_q.push_back(txn);
+ full_txn.start = 1;
+ if (is_read) full_txn.tran_id = this.exp_rd_id++;
+ // Address
+ `uvm_create_obj(i2c_item, txn)
+ `uvm_create_obj(i2c_item, exp_txn)
+ txn.drv_type = HostData;
+ txn.start = 1;
+ txn.wdata[7:1] = target_addr0;
+ txn.wdata[0] = is_read;
+ txn.tran_id = this.tran_id++;
+ `downcast(exp_txn, txn.clone());
+ dst_q.push_back(txn);
+ full_txn.addr = txn.wdata[7:1];
+ full_txn.read = is_read;
+
+ p_sequencer.target_mode_wr_exp_port.write(exp_txn);
+ cfg.sent_acq_cnt++;
+
+ if (is_read) begin
+ read_size = src_q.size();
+ read_rcvd.push_back(read_size);
+ end
+ // Data
+ while (src_q.size() > 0) begin
+ `uvm_create_obj(i2c_item, txn)
+ txn = src_q.pop_front();
+ if (txn.drv_type != HostRStart) begin
+ // Restart only has empty data for address holder
+ full_txn.data_q.push_back(txn.wdata);
+ end
+
+ // RS creates 2 extra acq entry
+ // one for RS
+ // the other for a new start acq_entry with address
+ if (txn.drv_type == HostRStart) begin
+ bit prv_read = 0;
+ `uvm_create_obj(i2c_item, exp_txn)
+ exp_txn.drv_type = HostRStart;
+ exp_txn.rstart = 1;
+ exp_txn.tran_id = this.tran_id++;
+ p_sequencer.target_mode_wr_exp_port.write(exp_txn);
+ cfg.sent_acq_cnt++;
+ `uvm_create_obj(i2c_item, rs_txn)
+ `downcast(rs_txn, txn.clone())
+ dst_q.push_back(txn);
+
+ rs_txn.drv_type = HostData;
+ rs_txn.start = 1;
+ rs_txn.rstart = 0;
+ rs_txn.wdata[7:1] = target_addr1;
+ prv_read = is_read;
+ is_read = rs_txn.read;
+ rs_txn.wdata[0] = is_read;
+ dst_q.push_back(rs_txn);
+ // create a separate stat/addr entry for exp
+ `uvm_create_obj(i2c_item, exp_txn)
+ `downcast(exp_txn, rs_txn.clone());
+ exp_txn.tran_id = this.tran_id++;
+ p_sequencer.target_mode_wr_exp_port.write(exp_txn);
+ cfg.sent_acq_cnt++;
+ // fetch previous full_txn and creat a new one
+ if (prv_read) begin
+ full_txn.stop = 1;
+ p_sequencer.target_mode_rd_exp_port.write(full_txn);
+ end
+ `uvm_create_obj(i2c_item, full_txn)
+ `downcast(full_txn, rs_txn);
+ if (is_read) begin
+ full_txn.tran_id = exp_rd_id++;
+ end
+ end else begin
+ if (is_read) begin
+ i2c_item read_txn;
+ `uvm_create_obj(i2c_item, read_txn)
+ `downcast(read_txn, txn.clone())
+ full_txn.num_data++;
+ if (src_q.size() == 0) begin
+ txn.drv_type = HostNAck;
+ end else begin
+ // if your next item is restart Do nack
+ if (src_q[0].drv_type == HostRStart) txn.drv_type = HostNAck;
+ else txn.drv_type = HostAck;
+ end
+ dst_q.push_back(txn);
+ read_txn_q.push_back(read_txn);
+ end else begin
+ `downcast(exp_txn, txn.clone());
+ // Add RS transaction to driver only
+ // and create address transaction after
+ dst_q.push_back(txn);
+ exp_txn.tran_id = this.tran_id++;
+ p_sequencer.target_mode_wr_exp_port.write(exp_txn);
+ cfg.sent_acq_cnt++;
+ end
+ end
+ end // while (src_q.size() > 0)
+
+ // Stop
+ `uvm_create_obj(i2c_item, txn)
+ `uvm_create_obj(i2c_item, exp_txn)
+ txn.tran_id = this.tran_id++;
+ txn.stop = 1;
+ txn.drv_type = HostStop;
+ `downcast(exp_txn, txn.clone());
+ dst_q.push_back(txn);
+ full_txn.stop = 1;
+ p_sequencer.target_mode_wr_exp_port.write(exp_txn);
+ cfg.sent_acq_cnt++;
+ if (is_read) begin
+ p_sequencer.target_mode_rd_exp_port.write(full_txn);
+ end
+ endfunction
+
endclass : i2c_base_vseq
diff --git a/hw/ip/i2c/dv/env/seq_lib/i2c_target_smoke_vseq.sv b/hw/ip/i2c/dv/env/seq_lib/i2c_target_smoke_vseq.sv
index 754c268..58042c1 100644
--- a/hw/ip/i2c/dv/env/seq_lib/i2c_target_smoke_vseq.sv
+++ b/hw/ip/i2c/dv/env/seq_lib/i2c_target_smoke_vseq.sv
@@ -7,110 +7,39 @@
`uvm_object_utils(i2c_target_smoke_vseq)
`uvm_object_new
- int tran_id;
-
virtual task body();
i2c_target_base_seq m_i2c_host_seq;
+ i2c_item txn_q[$];
// Intialize dut in device mode and agent in host mode
initialization(Device);
+ `uvm_info("cfg_summary", $sformatf("target_addr0:0x%x target_addr1:0x%x num_trans:%0d",
+ target_addr0, target_addr1, num_trans), UVM_MEDIUM)
+ print_time_property();
- for (int i = 0; i < 2; i++) begin
- get_timing_values();
- program_registers();
+ fork
+ begin
+ for (int i = 0; i < num_trans; i++) begin
+ get_timing_values();
+ if (i > 0) begin
+ // wait for previous stop before program a new timing param.
+ @(cfg.m_i2c_agent_cfg.got_stop);
+ end
+ program_registers();
- `uvm_create_obj(i2c_target_base_seq, m_i2c_host_seq)
-
- create_write_txn(m_i2c_host_seq);
- m_i2c_host_seq.start(p_sequencer.i2c_sequencer_h);
- end
+ `uvm_create_obj(i2c_target_base_seq, m_i2c_host_seq)
+ create_txn(txn_q);
+ fetch_txn(txn_q, m_i2c_host_seq.req_q);
+ m_i2c_host_seq.start(p_sequencer.i2c_sequencer_h);
+ end
+ end
+ begin
+ process_acq();
+ end
+ begin
+ process_txq();
+ end
+ join_none
endtask : body
- // Use for debug only
- function void print_time_property();
- `uvm_info(`gfn, $sformatf("timing_prop"), UVM_MEDIUM)
- // high period of the SCL in clock units
- `uvm_info(`gfn, $sformatf("thigh:%0d", thigh), UVM_MEDIUM);
- // low period of the SCL in clock units
- `uvm_info(`gfn, $sformatf("tlow:%0d", tlow), UVM_MEDIUM);
- // rise time of both SDA and SCL in clock units
- `uvm_info(`gfn, $sformatf("t_r:%0d", t_r), UVM_MEDIUM);
- // fall time of both SDA and SCL in clock units
- `uvm_info(`gfn, $sformatf("t_f:%0d", t_f), UVM_MEDIUM);
- // hold time for (repeated) START in clock units
- `uvm_info(`gfn, $sformatf("thd_sta:%0d", thd_sta), UVM_MEDIUM);
- // setup time for repeated START in clock units
- `uvm_info(`gfn, $sformatf("tsu_sta:%0d", tsu_sta), UVM_MEDIUM);
- // setup time for STOP in clock units
- `uvm_info(`gfn, $sformatf("tsu_sto:%0d", tsu_sto), UVM_MEDIUM);
- // data setup time in clock units
- `uvm_info(`gfn, $sformatf("tsu_dat:%0d", tsu_dat), UVM_MEDIUM);
- // data hold time in clock units
- `uvm_info(`gfn, $sformatf("thd_dat:%0d", thd_dat), UVM_MEDIUM);
- // bus free time between STOP and START in clock units
- `uvm_info(`gfn, $sformatf("t_buf:%0d", t_buf), UVM_MEDIUM);
- // max time target may stretch the clock
- `uvm_info(`gfn, $sformatf("t_timeout:%0d", t_timeout), UVM_MEDIUM);
- // max time target may stretch the clock
- `uvm_info(`gfn, $sformatf("e_timeout:%0d", e_timeout), UVM_MEDIUM);
- // sda unstable time during the posedge_clock
- `uvm_info(`gfn, $sformatf("t_sda_unstable:%0d", t_sda_unstable), UVM_MEDIUM);
- // sda interference time during the posedge_clock
- `uvm_info(`gfn, $sformatf("t_sda_interference:%0d", t_sda_interference), UVM_MEDIUM);
- // scl interference time during the posedge_clock
- `uvm_info(`gfn, $sformatf("t_scl_interference:%0d", t_scl_interference), UVM_MEDIUM);
- `uvm_info(`gfn, $sformatf("error intrs probability"), UVM_MEDIUM)
- `uvm_info(`gfn, $sformatf("prob_sda_unstable:%0d ", prob_sda_unstable), UVM_MEDIUM);
- `uvm_info(`gfn, $sformatf("prob_sda_interference:%0d", prob_sda_interference), UVM_MEDIUM);
- `uvm_info(`gfn, $sformatf("prob_scl_interference:%0d", prob_scl_interference), UVM_MEDIUM);
- endfunction
-
- task create_write_txn(ref i2c_target_base_seq seq);
- bit [7:0] wdata_q[$];
- i2c_item txn;
- i2c_item exp_txn;
-
- int txn_size;
-
- `uvm_create_obj(i2c_item, txn)
- `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(wdata_q,
- wdata_q.size() inside {
- [cfg.seq_cfg.min_data : cfg.seq_cfg.max_data]};)
- // data + address
- `uvm_info(`gfn, $sformatf("byte0:0x%x (addr:0x%x) wdataq:%p",
- {target_addr0, 1'b0}, target_addr0, wdata_q), UVM_MEDIUM)
- txn_size = wdata_q.size() + 1;
- txn.drv_type = HostStart;
- // skip the first transaction to pass sb because
- // start and address are coalescing in acq fifo.
- seq.req_q.push_back(txn);
- for (int i = 0; i < txn_size; i++) begin
- `uvm_create_obj(i2c_item, txn)
- `uvm_create_obj(i2c_item, exp_txn)
- txn.drv_type = HostData;
- txn.stop = 0;
- txn.tran_id = this.tran_id++;
- if (i == 0) begin
- txn.start = 1;
- txn.wdata[7:1] = target_addr0;
- txn.wdata[0] = 1'b0;
-
- end else begin
- txn.start = 0;
- txn.wdata = wdata_q[i-1];
- end
-
- `downcast(exp_txn, txn.clone());
- seq.req_q.push_back(txn);
- p_sequencer.target_mode_wr_exp_port.write(exp_txn);
- end
- `uvm_create_obj(i2c_item, txn)
- `uvm_create_obj(i2c_item, exp_txn)
- txn.tran_id = this.tran_id++;
- txn.stop = 1;
- txn.drv_type = HostStop;
- `downcast(exp_txn, txn.clone());
- seq.req_q.push_back(txn);
- p_sequencer.target_mode_wr_exp_port.write(exp_txn);
- endtask
endclass : i2c_target_smoke_vseq
diff --git a/hw/ip/i2c/dv/i2c_sim_cfg.hjson b/hw/ip/i2c/dv/i2c_sim_cfg.hjson
index a3189de..9efa40d 100644
--- a/hw/ip/i2c/dv/i2c_sim_cfg.hjson
+++ b/hw/ip/i2c/dv/i2c_sim_cfg.hjson
@@ -123,7 +123,7 @@
{
name: i2c_target_smoke
uvm_test_seq: i2c_target_smoke_vseq
- run_opts: ["+i2c_agent_mode=Host", "+test_timeout_ns=100_000"]
+ run_opts: ["+i2c_agent_mode=Host", "+test_timeout_ns=10_000_000"]
}
]