blob: 9a4739ccf6bb670f6775a16cdbced6a08831d34b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This sequence use 'host_stretch_test_mode' in i2c_driver.
// Under host_stretch_test_mode, i2c_driver stretch scl at 'target ack' cycle.
// stretch cycle is determined to be greater than 't_timeout' vlaue.
// At the end of stretch event, 'process_stretch_timeout_intr' check
// StretchTimeout interrupt.
// In each transaction, for write cycle, host will get # of write byte + 1 (command) ack.
// For read cycle host will get 1 ack.
// cnt_wr/rd_stretch will evaluate following the above.
class i2c_host_stretch_timeout_vseq extends i2c_rx_tx_vseq;
`uvm_object_utils(i2c_host_stretch_timeout_vseq)
`uvm_object_new
// set timeout field to minimum value to ensure
// stretch_timeout irq is asserted for every target's ACK
// Re-write this constraint:
// Between scl_i / scl_o there are sync flops exist.
// This always creates 3 cycles of delay and increment stretch_idle_cnt up to 3.
// To avoid spurious interrupt, program timeout count value greater than 3.
// 't_timeout' is used to define upper bound of 'tStretchHostClock'
// see (https://cs.opensource.google/opentitan/opentitan/+/master:
// hw/dv/sv/i2c_agent/i2c_driver.sv;drc=95fba940c08451445fac85b1aac4a8117cee452b;
// l=107)
constraint t_timeout_c { t_timeout == 5; }
// timeout is always enabled so stretch_timeout irq is aggressively asserted
constraint e_timeout_c { e_timeout == 1; }
local uint cnt_wr_stretch;
local uint cnt_rd_stretch;
local bit check_wr_stretch;
local bit check_rd_stretch;
virtual task body();
`uvm_info(`gfn, "\n--> start of i2c_host_stretch_timeout_vseq", UVM_DEBUG)
cfg.m_i2c_agent_cfg.host_stretch_test_mode = 1;
initialization(.mode(Host));
for (int i = 1; i <= num_trans; i++) begin
cnt_wr_stretch = 0;
cnt_rd_stretch = 0;
check_wr_stretch = 1'b0;
check_rd_stretch = 1'b0;
`uvm_info(`gfn, $sformatf("\n run simulation %0d/%0d", i, num_trans), UVM_DEBUG)
fork
begin
check_wr_stretch = 1'b1;
host_send_trans(.max_trans(1), .trans_type(WriteOnly));
check_wr_stretch = 1'b0;
if (!cfg.under_reset) begin
// host clock is stretched for every target's ACK thus
// cnt_wr_stretch 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(cnt_wr_stretch, (num_wr_bytes + 1))
end
check_rd_stretch = 1'b1;
host_send_trans(.max_trans(1), .trans_type(ReadOnly));
check_rd_stretch = 1'b0;
if (!cfg.under_reset) begin
// check_rd_stretchretch_timeout must be equal to 1
// that is the target's ACK to response the address byte sent by host
`DV_CHECK_EQ(cnt_rd_stretch, 1)
end
end
begin
while (!cfg.under_reset &&
(check_wr_stretch || check_rd_stretch)) process_stretch_timeout_intr();
end
join
end
`uvm_info(`gfn, "\n--> end of i2c_host_stretch_timeout_vseq", UVM_DEBUG)
endtask : body
task process_stretch_timeout_intr();
bit stretch_timeout;
csr_rd(.ptr(ral.intr_state.stretch_timeout), .value(stretch_timeout));
if (stretch_timeout) begin
if (check_wr_stretch) cnt_wr_stretch++;
if (check_rd_stretch) cnt_rd_stretch++;
// 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);
cfg.clk_rst_vif.wait_clks(1);
clear_interrupt(StretchTimeout);
`uvm_info("proc_stretch_timeout_intr",
$sformatf("check_wr_st %b cnt_wr_st %0d, check_rd_st %b, cnt_rd_st %0d",
check_wr_stretch, cnt_wr_stretch, check_rd_stretch, cnt_rd_stretch), UVM_DEBUG)
end
endtask : process_stretch_timeout_intr
endclass : i2c_host_stretch_timeout_vseq