blob: e3c17cc35a58a6dece6f1ae5bd46b64a15b17f5b [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// test the threshold interrupt of fmt_fifo and rx_fifo
// TODO: Weicai's comments in PR #3128: consider constraining rx_fifo_access_dly
// to test threshold irq
class i2c_host_fifo_threshold_vseq extends i2c_rx_tx_vseq;
`uvm_object_utils(i2c_host_fifo_threshold_vseq)
`uvm_object_new
// fast write data to fmt_fifo to quickly trigger fmt_threshold interrupt
constraint fmt_fifo_access_dly_c { fmt_fifo_access_dly == 0;}
// fast read data from rd_fifo after crossing threshold level to quickly finish simulation
constraint rx_fifo_access_dly_c { rx_fifo_access_dly == 0;}
// set write transaction size to fmt_fifo depth is enough to cross the highest fmtilvl value
constraint num_wr_bytes_c { num_wr_bytes == I2C_FMT_FIFO_DEPTH; }
// read transaction length is equal to rx_fifo depth to cross rxilvl
constraint num_rd_bytes_c { num_rd_bytes == I2C_RX_FIFO_DEPTH; }
// counting the number of received threshold interrupts
local uint cnt_fmt_threshold;
local uint cnt_rx_threshold;
virtual task pre_start();
super.pre_start();
// config rx_threshold test (fmt_threshold test is configured by default)
cfg.seq_cfg.en_rx_threshold = 1'b1;
print_seq_cfg_vars("pre-start");
endtask : pre_start
virtual task body();
bit check_fmt_threshold, check_rx_threshold;
initialization(.mode(Host));
`uvm_info(`gfn, "\n--> start of i2c_host_fifo_threshold_vseq", UVM_DEBUG)
for (int i = 1; i <= num_trans; i++) begin
check_fmt_threshold = 1'b1;
check_rx_threshold = 1'b1;
cnt_fmt_threshold = 0;
cnt_rx_threshold = 0;
`uvm_info(`gfn, $sformatf("\n run simulation %0d/%0d", i, num_trans), UVM_DEBUG)
fork
begin
//*** verify fmt_threshold irq:
// -> send write transaction -> pooling and counting fmt_threshold interrupt
// -> check write complete -> stop pooling fmt_threshold interrupt
// -> verify the number of received fmt_threshold interrupt
if (check_fmt_threshold) begin
host_send_trans(.max_trans(1), .trans_type(WriteOnly));
check_fmt_threshold = 1'b0; // gracefully stop process_fmt_threshold_intr
// depending the programmed fmtivl and the DUT configuration
// (timing regsisters), cnt_fmt_threshold could be
// 1: fmtilvl is crossed one when data drains from fmt_fifo
// 2: fmtilvl is crossed twice when data fills up or drains from fmt_fifo
if (!cfg.under_reset) begin
`DV_CHECK_GT(cnt_fmt_threshold, 0)
`DV_CHECK_LE(cnt_fmt_threshold, 2)
`uvm_info(`gfn, $sformatf("\n cnt_fmt_threshold %0d", cnt_fmt_threshold), UVM_DEBUG)
end
end
//*** verify rx_threshold irq:
// -> send read transaction -> pooling and counting rx_threshold interrupt
// -> check read complete -> stop pooling rx_threshold interrupt
// -> verify the number of received rx_threshold interrupt
if (check_rx_threshold) begin
// first en_rx_threshold is unset to quickly fill up rx_fifo and
// threshold interrupt is assuredly triggered
// until rx_fifo becomes full, en_rx_threshold is set to start reading rx_fifo
host_send_trans(.max_trans(1), .trans_type(ReadOnly));
check_rx_threshold = 1'b0; // gracefully stop process_rx_threshold_intr
// for fmtilvl > 4, rx_threshold is disabled (cnt_rx_threshold = 0)
// otherwise, cnt_rx_threshold must be 1
if (!cfg.under_reset) begin
if ( rxilvl <= 4) begin
`DV_CHECK_EQ(cnt_rx_threshold, 1)
end else begin
`DV_CHECK_EQ(cnt_rx_threshold, 0)
end
// during a read transaction, fmt_threshold could be triggered since read address
// and control byte are programmed to fmt_fifo and possibly cross fmtilvl
// if fmt_threshold is triggered, then it should be cleared to not interfere
// counting fmt_threshold in the next transaction (no need to verify
// fmt_threshold again during read)
`uvm_info(`gfn, $sformatf("\n cnt_rx_threshold %0d", cnt_rx_threshold), UVM_DEBUG)
end
clear_interrupt(FmtThreshold);
end
end
begin
while (!cfg.under_reset && check_fmt_threshold) process_fmt_threshold_intr();
end
begin
while (!cfg.under_reset && check_rx_threshold) process_rx_threshold_intr();
end
join
end
`uvm_info(`gfn, "\n--> end of i2c_host_fifo_threshold_vseq", UVM_DEBUG)
endtask : body
task process_fmt_threshold_intr();
bit fmt_threshold;
bit [TL_DW-1:0] fmt_lvl, fmt_ilvl, intr_enable;
@(posedge cfg.clk_rst_vif.clk);
csr_rd(.ptr(ral.intr_enable), .value(intr_enable), .backdoor(1'b1));
if (intr_enable[FmtThreshold] && cfg.intr_vif.pins[FmtThreshold]) begin
cnt_fmt_threshold++;
// read registers via backdoor
csr_rd(.ptr(ral.fifo_ctrl.fmtilvl), .value(fmt_ilvl), .backdoor(1'b1));
csr_rd(.ptr(ral.fifo_status.fmtlvl), .value(fmt_lvl), .backdoor(1'b1));
`uvm_info(`gfn, $sformatf("\n fmtilvl %0d, fmtlvl %0d", fmt_ilvl, fmt_lvl), UVM_DEBUG)
// bound checking for fmt_lvl w.r.t fmt_ilvl because rx_fifo can received an extra data
// before fmt_threshold intr pin is asserted (corner case)
if (!cfg.under_reset) begin
case (fmt_ilvl)
0: bound_check(fmt_lvl, 1, 2);
1: bound_check(fmt_lvl, 4, 5);
2: bound_check(fmt_lvl, 8, 9);
default: bound_check(fmt_lvl, 16, 17);
endcase
end
clear_interrupt(FmtThreshold);
end
endtask : process_fmt_threshold_intr
task process_rx_threshold_intr();
bit rx_threshold;
bit [TL_DW-1:0] rx_lvl, rx_ilvl, intr_enable;
@(posedge cfg.clk_rst_vif.clk);
csr_rd(.ptr(ral.intr_enable), .value(intr_enable), .backdoor(1'b1));
if (intr_enable[RxThreshold] && cfg.intr_vif.pins[RxThreshold]) begin
cnt_rx_threshold++;
// read registers via backdoor
csr_rd(.ptr(ral.fifo_status.rxlvl), .value(rx_lvl), .backdoor(1'b1));
csr_rd(.ptr(ral.fifo_ctrl.rxilvl), .value(rx_ilvl), .backdoor(1'b1));
// bound checking for rx_lvl w.r.t rx_ilvl because rx_fifo can received an extra data
// before rx_threshold intr pin is asserted (corner case)
if (!cfg.under_reset) begin
case (rx_ilvl)
0: bound_check(rx_lvl, 1, 2);
1: bound_check(rx_lvl, 4, 5);
2: bound_check(rx_lvl, 8, 9);
3: bound_check(rx_lvl, 16, 17);
4: bound_check(rx_lvl, 30, 31);
default: `uvm_error(`gfn, "\n Invalid rx_ilvl")
endcase
end
clear_interrupt(RxThreshold);
end
endtask : process_rx_threshold_intr
endclass : i2c_host_fifo_threshold_vseq