[spi_device/dv] Add interrupt seq
spi_device:
1. Add interrupt seq to test interrupts directly and adjust some seq for
reuse
2. Add intr_test coverage sample
3. Fix underflow_overflow corner issue
common dv:
1. Add max2 min2 functions
2. update check_interrups function to use intr_enable
Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/cip_lib/cip_base_vseq.sv b/hw/dv/sv/cip_lib/cip_base_vseq.sv
index a8a87be..7e6bae5 100644
--- a/hw/dv/sv/cip_lib/cip_base_vseq.sv
+++ b/hw/dv/sv/cip_lib/cip_base_vseq.sv
@@ -213,30 +213,28 @@
int indices[$] = {},
uvm_reg_block scope = null,
bit [TL_DW-1:0] clear = '1);
- uvm_reg csr;
+ uvm_reg csr_intr_state, csr_intr_enable;
bit [TL_DW-1:0] act_pins;
bit [TL_DW-1:0] exp_pins;
bit [TL_DW-1:0] exp_intr_state;
+ if (cfg.under_reset) return;
+
act_pins = cfg.intr_vif.sample() & interrupts;
if (check_set) begin
- exp_pins = interrupts;
+ csr_intr_enable = get_interrupt_csr("intr_enable", "", indices, scope);
+ exp_pins = interrupts & csr_intr_enable.get_mirrored_value();
exp_intr_state = interrupts;
end else begin
exp_pins = '0;
exp_intr_state = ~interrupts;
end
- // if reset, pin should be reset to 0
- if (!cfg.clk_rst_vif.rst_n) begin
- exp_pins = '0;
- exp_intr_state = '0;
- `uvm_info(`gfn, "interrupt pin expect value set to 0 due to reset", UVM_LOW)
- end
- if (!cfg.under_reset) `DV_CHECK_EQ(act_pins, exp_pins)
- csr = get_interrupt_csr("intr_state", "", indices, scope);
- csr_rd_check(.ptr(csr), .compare_value(exp_intr_state), .compare_mask(interrupts));
+ `DV_CHECK_EQ(act_pins, exp_pins)
+ csr_intr_state = get_interrupt_csr("intr_state", "", indices, scope);
+ csr_rd_check(.ptr(csr_intr_state), .compare_value(exp_intr_state), .compare_mask(interrupts));
+
if (check_set && |(interrupts & clear)) begin
- csr_wr(.csr(csr), .value(interrupts & clear));
+ csr_wr(.csr(csr_intr_state), .value(interrupts & clear));
end
endtask
diff --git a/hw/dv/sv/dv_utils/dv_utils_pkg.sv b/hw/dv/sv/dv_utils/dv_utils_pkg.sv
index 2ba3987..c6e8060 100644
--- a/hw/dv/sv/dv_utils/dv_utils_pkg.sv
+++ b/hw/dv/sv/dv_utils/dv_utils_pkg.sv
@@ -76,6 +76,16 @@
string msg_id = "dv_utils_pkg";
+ // return the smaller value of 2 inputs
+ function automatic int min2(int a, int b);
+ return (a < b) ? a : b;
+ endfunction
+
+ // return the bigger value of 2 inputs
+ function automatic int max2(int a, int b);
+ return (a > b) ? a : b;
+ endfunction
+
// Simple function to set max errors before quitting sim
function automatic void set_max_quit_count(int n);
uvm_report_server report_server = uvm_report_server::get_server();
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv
index 40f811f..cd8fb8a 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv
@@ -24,6 +24,14 @@
rand uint sram_host_limit_addr;
rand uint sram_device_base_addr;
rand uint sram_device_limit_addr;
+ // helper variables
+ rand uint num_host_sram_words;
+ rand uint num_device_sram_words;
+ rand uint sram_host_byte_size;
+ rand uint sram_device_byte_size;
+
+ rand uint tx_watermark_lvl;
+ rand uint rx_watermark_lvl;
// core clk freq / spi clk freq is from 1/4 to 8. use below 2 var to represent the ratio
// if spi_freq_faster, core_spi_freq_ratio = spi clk freq / core clk freq (1:4)
@@ -40,6 +48,31 @@
sram_device_limit_addr == 32'h3ff; // 512 bytes
}
+ constraint sram_size_c {
+ solve num_host_sram_words before sram_host_byte_size;
+ solve num_device_sram_words before sram_device_byte_size;
+ num_host_sram_words == sram_host_limit_addr[31:2] - sram_host_base_addr[31:2] + 1;
+ num_device_sram_words == sram_device_limit_addr[31:2] - sram_device_base_addr[31:2] + 1;
+ sram_host_byte_size == num_host_sram_words << 2;
+ sram_device_byte_size == num_device_sram_words << 2;
+ }
+
+ constraint tx_watermark_lvl_c {
+ tx_watermark_lvl dist {
+ [0 : SRAM_WORD_SIZE] :/ 1, // first 2 words
+ [SRAM_WORD_SIZE+1 : sram_host_byte_size-1-SRAM_WORD_SIZE] :/ 7,
+ [sram_host_byte_size-SRAM_WORD_SIZE : sram_host_byte_size] :/ 1, // max 2 words
+ [sram_host_byte_size+1 : SRAM_SIZE] :/ 1};// over the max size
+ }
+
+ constraint rx_watermark_lvl_c {
+ rx_watermark_lvl dist {
+ [0 : SRAM_WORD_SIZE] :/ 1, // first 2 words
+ [SRAM_WORD_SIZE+1 : sram_device_byte_size-1-SRAM_WORD_SIZE] :/ 7,
+ [sram_device_byte_size-SRAM_WORD_SIZE : sram_device_byte_size] :/ 1, // max 2 words
+ [sram_device_byte_size+1 : SRAM_SIZE] :/ 1};// over the max size
+ }
+
// core clk freq / spi clk freq is from 1/4 to 8
constraint freq_c {
core_spi_freq_ratio inside {[1:8]};
@@ -97,11 +130,25 @@
ral.cfg.rx_order.set(host_bit_dir);
//ral.cfg.timer_v.set(rx_timer); TODO do it later
csr_update(.csr(ral.cfg));
+
+ // watermark
+ ral.fifo_level.txlvl.set(tx_watermark_lvl);
+ ral.fifo_level.rxlvl.set(rx_watermark_lvl);
+ csr_update(.csr(ral.fifo_level));
+
+ // intr_enable
+ `DV_CHECK_RANDOMIZE_FATAL(ral.intr_enable)
+ csr_update(.csr(ral.intr_enable));
+
if (do_spi_device_mem_cfg) begin
set_sram_host_addr_range(sram_host_base_addr, sram_host_limit_addr);
set_sram_device_addr_range(sram_device_base_addr, sram_device_limit_addr);
// only configure sram once
do_spi_device_mem_cfg = 0;
+ sram_host_base_addr.rand_mode(0);
+ sram_host_limit_addr.rand_mode(0);
+ sram_device_base_addr.rand_mode(0);
+ sram_device_limit_addr.rand_mode(0);
end
endtask
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_extreme_fifo_size_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_extreme_fifo_size_vseq.sv
index 9c2ec58..6afc813 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_extreme_fifo_size_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_extreme_fifo_size_vseq.sv
@@ -8,13 +8,13 @@
`uvm_object_new
constraint sram_size_constraints_c {
- host_sram_word_size dist {
+ num_host_sram_words dist {
1 :/ 1, // 1 word
SRAM_SIZE[31:2]/2 :/ 1, // half of the total mem
SRAM_SIZE[31:2]-1 :/ 1, // max size
[2:SRAM_SIZE[31:2]-2] :/ 1
};
- device_sram_word_size dist {
+ num_device_sram_words dist {
1 :/ 1, // 1 word
SRAM_SIZE[31:2]/2 :/ 1, // half of the total mem
SRAM_SIZE[31:2]-1 :/ 1, // max size
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_fifo_underflow_overflow_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_fifo_underflow_overflow_vseq.sv
index 1b96f5d..369a90a 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_fifo_underflow_overflow_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_fifo_underflow_overflow_vseq.sv
@@ -30,13 +30,13 @@
// there are some underflow data in fifo, clean them up
// repeat twice in case some data in async_fifo when sram fifo is full
for (uint i = 0; i < 2; i++) begin
+ cfg.clk_rst_vif.wait_clks(2); // 2 cycle for fifo ptr to be updated
read_rx_avail_bytes(SramDataAvail, rx_avail_bytes);
if (rx_avail_bytes == 0) break;
read_host_words_rcvd(rx_avail_bytes / SRAM_WORD_SIZE, device_words_q);
// in case data is transferred from async fifo, wait until transfer is done
if (i == 0) begin
csr_spinwait(.ptr(ral.async_fifo_level.rxlvl), .exp_data(0));
- cfg.clk_rst_vif.wait_clks(2); // 2 cycle for fifo ptr to be updated
end
end
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_intr_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_intr_vseq.sv
new file mode 100644
index 0000000..b6a2b55
--- /dev/null
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_intr_vseq.sv
@@ -0,0 +1,162 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// directly test all the interrupt one by one
+class spi_device_intr_vseq extends spi_device_txrx_vseq;
+ `uvm_object_utils(spi_device_intr_vseq)
+ `uvm_object_new
+
+ virtual task body();
+ spi_device_intr_e spi_dev_intr;
+ bit is_tx_async_fifo_filled;
+
+ for (int i = 1; i <= num_trans; i++) begin
+ `DV_CHECK_RANDOMIZE_FATAL(this)
+ spi_device_init();
+
+ // fill tx async fifo to avoid sending out unknown data
+ if (!is_tx_async_fifo_filled) begin
+ bit [7:0] device_bytes_q[$];
+ // fill the fifo and wait until data is ready
+ process_tx_write(ASYNC_FIFO_SIZE);
+ csr_spinwait(.ptr(ral.async_fifo_level.txlvl), .exp_data(ASYNC_FIFO_SIZE));
+ // clean up tx fifo
+ spi_host_xfer_bytes(ASYNC_FIFO_SIZE, device_bytes_q);
+ // clean up rx fifo
+ process_rx_read(ASYNC_FIFO_SIZE);
+ // clean interrupts
+ csr_wr(.csr(ral.intr_state), .value('1));
+ end
+
+ repeat (NumSpiDevIntr) begin
+ `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(spi_dev_intr,
+ spi_dev_intr != NumSpiDevIntr;)
+ `uvm_info(`gfn, $sformatf("\nTesting %0s", spi_dev_intr.name), UVM_LOW)
+ drive_and_check_one_intr(spi_dev_intr);
+
+ csr_wr(.csr(ral.intr_state), .value('1));
+ check_for_tx_rx_idle();
+ end
+ `uvm_info(`gfn, $sformatf("finished run %0d/%0d", i, num_trans), UVM_LOW)
+ end
+
+ endtask : body
+
+ task drive_and_check_one_intr(spi_device_intr_e spi_dev_intr);
+ bit [7:0] device_bytes_q[$];
+ uint avail_bytes;
+
+ case (spi_dev_intr)
+ RxFifoFull, RxFifoOverflow: begin // test fifo full and overflow together
+ // just below fifo full
+ spi_host_xfer_bytes(sram_host_byte_size - SRAM_WORD_SIZE, device_bytes_q);
+ wait_for_rx_avail_bytes(sram_host_byte_size - SRAM_WORD_SIZE, SramDataAvail, avail_bytes);
+ check_interrupts(.interrupts(1 << RxFifoFull), .check_set(0));
+
+ // fifo should be full
+ spi_host_xfer_bytes(SRAM_WORD_SIZE, device_bytes_q);
+ wait_for_rx_avail_bytes(sram_host_byte_size, SramDataAvail, avail_bytes);
+ check_interrupts(.interrupts(1 << RxFifoFull), .check_set(1));
+
+ // fill async fifo and check fifo doesn't overflow
+ spi_host_xfer_bytes(ASYNC_FIFO_SIZE, device_bytes_q);
+ cfg.clk_rst_vif.wait_clks(2); // for interrupt to triggered
+ check_interrupts(.interrupts(1 << RxFifoOverflow), .check_set(0));
+
+ // fill 1 word and check fifo overflow
+ spi_host_xfer_bytes(SRAM_WORD_SIZE, device_bytes_q);
+ check_interrupts(.interrupts(1 << RxFifoOverflow), .check_set(1));
+ check_interrupts(.interrupts(1 << RxFifoGeLevel),
+ .check_set(rx_watermark_lvl inside {[1:sram_host_byte_size]}));
+
+ // clean up rx fifo
+ process_rx_read(sram_host_byte_size + ASYNC_FIFO_SIZE);
+ end
+ RxFifoGeLevel: begin
+ uint aligned_watermark = (rx_watermark_lvl >> 2) << 2; // remove lsb 2bits
+ uint filled_bytes;
+
+ if (rx_watermark_lvl[1:0] > 0) aligned_watermark += SRAM_WORD_SIZE;
+
+ if (rx_watermark_lvl > 0 && aligned_watermark < sram_host_byte_size) begin
+ // just below watermark
+ if (aligned_watermark - SRAM_WORD_SIZE > 0) begin
+ spi_host_xfer_bytes(aligned_watermark - SRAM_WORD_SIZE, device_bytes_q);
+ wait_for_rx_avail_bytes(aligned_watermark - SRAM_WORD_SIZE, SramDataAvail, avail_bytes);
+ check_interrupts(.interrupts(1 << RxFifoGeLevel), .check_set(0));
+ end
+ // equal to watermark
+ spi_host_xfer_bytes(SRAM_WORD_SIZE, device_bytes_q);
+ wait_for_rx_avail_bytes(aligned_watermark, SramDataAvail, avail_bytes);
+ check_interrupts(.interrupts(1 << RxFifoGeLevel), .check_set(1));
+
+ // clean interrupts and test it's edge triggered
+ filled_bytes = aligned_watermark + SRAM_WORD_SIZE;
+ csr_wr(.csr(ral.intr_state), .value('1));
+ spi_host_xfer_bytes(SRAM_WORD_SIZE, device_bytes_q);
+ wait_for_rx_avail_bytes(filled_bytes, SramDataAvail, avail_bytes);
+ check_interrupts(.interrupts(1 << RxFifoGeLevel), .check_set(0));
+
+ // clean up rx fifo
+ process_rx_read(filled_bytes);
+ end
+ end
+ TxFifoLtLevel: begin
+ uint aligned_watermark = (tx_watermark_lvl >> 2) << 2; // remove lsb 2bits
+ uint filled_bytes;
+
+ if (tx_watermark_lvl[1:0] > 0) aligned_watermark += SRAM_WORD_SIZE;
+
+ if (tx_watermark_lvl == 0 || tx_watermark_lvl > sram_device_byte_size) begin // no intr
+ // fill the sram fifo and async fifo, als wait until data is ready
+ process_tx_write(sram_device_byte_size + SRAM_WORD_SIZE);
+ wait_for_tx_avail_bytes(sram_device_byte_size, SramDataAvail, avail_bytes);
+
+ // clean up tx fifo
+ spi_host_xfer_bytes(sram_device_byte_size + SRAM_WORD_SIZE, device_bytes_q);
+
+ // clean up rx fifo
+ process_rx_read(dv_utils_pkg::min2(sram_host_byte_size + ASYNC_FIFO_SIZE,
+ sram_device_byte_size + SRAM_WORD_SIZE));
+ // check no interrupt since tx_watermark_lvl is 0 or over the max size
+ check_interrupts(.interrupts(1 << TxFifoLtLevel), .check_set(0));
+ end else begin
+ // fill async fifo, design has 2 words depth, but only update ptr to 2nd word when 1st
+ // one is out
+ process_tx_write(SRAM_WORD_SIZE);
+ // just at watermark
+ if (aligned_watermark != 0) process_tx_write(aligned_watermark);
+ else csr_spinwait(.ptr(ral.async_fifo_level.txlvl), .exp_data(SRAM_WORD_SIZE));
+ if (aligned_watermark > ASYNC_FIFO_SIZE) begin
+ check_interrupts(.interrupts(1 << TxFifoLtLevel), .check_set(0));
+ end
+
+ // send one word and fifo is less than watermark
+ spi_host_xfer_bytes(SRAM_WORD_SIZE, device_bytes_q);
+ cfg.clk_rst_vif.wait_clks(2); // for interrupt to triggered
+ check_interrupts(.interrupts(1 << TxFifoLtLevel), .check_set(1));
+
+ // clean up tx fifo
+ if (aligned_watermark != 0) spi_host_xfer_bytes(aligned_watermark, device_bytes_q);
+
+ // clean up rx fifo
+ process_rx_read(dv_utils_pkg::min2(sram_host_byte_size + ASYNC_FIFO_SIZE,
+ aligned_watermark + SRAM_WORD_SIZE));
+ end
+ end
+ RxFwModeErr: begin
+ // TODO, do it later
+ end
+ TxFifoUnderflow: begin
+ // send one word when fifo is empty
+ spi_host_xfer_bytes(SRAM_WORD_SIZE, device_bytes_q);
+ cfg.clk_rst_vif.wait_clks(2); // for interrupt to triggered
+ check_interrupts(.interrupts(1 << TxFifoUnderflow), .check_set(1));
+
+ // clean up rx fifo
+ process_rx_read(SRAM_WORD_SIZE);
+ end
+ endcase
+ endtask : drive_and_check_one_intr
+endclass : spi_device_intr_vseq
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_txrx_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_txrx_vseq.sv
index 9b0d192..972526d 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_txrx_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_txrx_vseq.sv
@@ -20,10 +20,6 @@
rand uint rx_delay;
rand uint spi_delay;
- // helper variables for sram randomization
- rand uint host_sram_word_size;
- rand uint device_sram_word_size;
-
rand bit en_dummy_host_xfer;
rand bit en_extra_dly;
@@ -76,7 +72,7 @@
}
// lower 2 bits are ignored, use word granularity to contrain the sram setting
- constraint sram_constraints_c {
+ constraint sram_addr_c {
// if limit is 0, it means 1 word
sram_host_limit_addr[31:2] < (SRAM_SIZE/SRAM_WORD_SIZE);
sram_device_limit_addr[31:2] < (SRAM_SIZE/SRAM_WORD_SIZE);
@@ -91,16 +87,14 @@
sram_device_limit_addr[31:2] < sram_host_base_addr[31:2];
sram_host_limit_addr < SRAM_SIZE;
}
- host_sram_word_size == sram_host_limit_addr[31:2] - sram_host_base_addr[31:2] + 1;
- device_sram_word_size == sram_device_limit_addr[31:2] - sram_device_base_addr[31:2] + 1;
}
// size from 25 to SRAM_SIZE/SRAM_WORD_SIZE-25
// override it if test extreme cases
constraint sram_size_constraints_c {
- host_sram_word_size inside {[25:SRAM_SIZE/SRAM_WORD_SIZE]};
- device_sram_word_size inside {[25:SRAM_SIZE/SRAM_WORD_SIZE]};
- host_sram_word_size == device_sram_word_size dist {
+ num_host_sram_words inside {[25:SRAM_SIZE/SRAM_WORD_SIZE]};
+ num_device_sram_words inside {[25:SRAM_SIZE/SRAM_WORD_SIZE]};
+ num_host_sram_words == num_device_sram_words dist {
1 :/ 2,
0 :/ 1
};
@@ -121,11 +115,11 @@
spi_device_init();
fork
begin
- process_tx_write();
+ process_tx_write(tx_total_bytes);
done_tx_write = 1;
end
begin
- process_rx_read();
+ process_rx_read(rx_total_bytes);
done_rx_read = 1;
end
begin
@@ -144,11 +138,10 @@
end // for
endtask : body
- virtual task process_tx_write();
- uint remaining_bytes = tx_total_bytes;
+ virtual task process_tx_write(uint xfer_bytes);
uint sram_avail_bytes;
uint tx_write_bytes;
- while (remaining_bytes > 0) begin
+ while (xfer_bytes > 0) begin
bit [31:0] device_words_q[$];
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(tx_delay)
cfg.clk_rst_vif.wait_clks(tx_delay);
@@ -156,7 +149,7 @@
wait_for_tx_avail_bytes(SRAM_WORD_SIZE, SramSpaceAvail, sram_avail_bytes);
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(tx_write_bytes,
tx_write_bytes <= sram_avail_bytes;
- tx_write_bytes <= remaining_bytes;
+ tx_write_bytes <= xfer_bytes;
tx_write_bytes[1:0] == 0;
tx_write_bytes dist {
[1:SRAM_WORD_SIZE] :/ 1,
@@ -165,8 +158,8 @@
SRAM_SIZE :/ 1};)
repeat (tx_write_bytes / SRAM_WORD_SIZE) device_words_q.push_back($urandom);
`uvm_info(`gfn, $sformatf("tx_write_bytes = %0d, sram_avail_bytes = %0d,\
- remaining_bytes = %0d",
- tx_write_bytes, sram_avail_bytes, remaining_bytes), UVM_MEDIUM)
+ xfer_bytes = %0d",
+ tx_write_bytes, sram_avail_bytes, xfer_bytes), UVM_MEDIUM)
// make sure ptr isn't being updated while fifo underflow is happening
if (allow_underflow_overflow) tx_ptr_sema.get();
@@ -178,16 +171,15 @@
tx_ptr_sema.put();
end
- remaining_bytes -= tx_write_bytes;
+ xfer_bytes -= tx_write_bytes;
end
`uvm_info(`gfn, "done process_tx_write", UVM_MEDIUM)
endtask : process_tx_write
- virtual task process_rx_read();
- int remaining_bytes = rx_total_bytes;
+ virtual task process_rx_read(uint xfer_bytes);
uint sram_avail_bytes;
uint rx_read_bytes;
- while (remaining_bytes > 0) begin
+ while (xfer_bytes > 0) begin
bit [31:0] device_words_q[$];
`DV_CHECK_MEMBER_RANDOMIZE_FATAL(rx_delay)
cfg.clk_rst_vif.wait_clks(rx_delay);
@@ -195,22 +187,22 @@
wait_for_rx_avail_bytes(SRAM_WORD_SIZE, SramDataAvail, sram_avail_bytes);
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(rx_read_bytes,
rx_read_bytes <= sram_avail_bytes;
- rx_read_bytes <= remaining_bytes;
+ rx_read_bytes <= xfer_bytes;
rx_read_bytes[1:0] == 0;
rx_read_bytes dist {
[1:SRAM_WORD_SIZE] :/ 1,
[SRAM_WORD_SIZE+1:20] :/ 3,
[21:SRAM_SIZE-1] :/ 1,
SRAM_SIZE :/ 1};)
- `uvm_info(`gfn, $sformatf("rx_read_bytes = %0d, sram_avail_bytes = %0d, remaining_bytes =%0d",
- rx_read_bytes, sram_avail_bytes, remaining_bytes), UVM_MEDIUM)
+ `uvm_info(`gfn, $sformatf("rx_read_bytes = %0d, sram_avail_bytes = %0d, xfer_bytes =%0d",
+ rx_read_bytes, sram_avail_bytes, xfer_bytes), UVM_MEDIUM)
// make sure ptr isn't being updated while fifo overflow is happening
if (allow_underflow_overflow) rx_ptr_sema.get();
read_host_words_rcvd(rx_read_bytes / SRAM_WORD_SIZE, device_words_q);
if (allow_underflow_overflow) rx_ptr_sema.put();
- remaining_bytes -= rx_read_bytes;
+ xfer_bytes -= rx_read_bytes;
end
`uvm_info(`gfn, "done process_rx_read", UVM_MEDIUM)
endtask : process_rx_read
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv
index c98998e..44395ea 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_vseq_list.sv
@@ -10,3 +10,4 @@
`include "spi_device_fifo_underflow_overflow_vseq.sv"
`include "spi_device_extreme_fifo_size_vseq.sv"
`include "spi_device_dummy_item_extra_dly_vseq.sv"
+`include "spi_device_intr_vseq.sv"
diff --git a/hw/ip/spi_device/dv/env/spi_device_env.core b/hw/ip/spi_device/dv/env/spi_device_env.core
index 2ab1222..5d611d1 100644
--- a/hw/ip/spi_device/dv/env/spi_device_env.core
+++ b/hw/ip/spi_device/dv/env/spi_device_env.core
@@ -26,6 +26,7 @@
- seq_lib/spi_device_txrx_vseq.sv: {is_include_file: true}
- seq_lib/spi_device_fifo_full_vseq.sv: {is_include_file: true}
- seq_lib/spi_device_dummy_item_extra_dly_vseq.sv: {is_include_file: true}
+ - seq_lib/spi_device_intr_vseq.sv: {is_include_file: true}
file_type: systemVerilogSource
targets:
diff --git a/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv b/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv
index aef405f..199d40c 100644
--- a/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv
@@ -22,11 +22,12 @@
// local parameters and types
typedef enum {
RxFifoFull,
- RxFifoGtLevel,
+ RxFifoGeLevel,
TxFifoLtLevel,
RxFwModeErr,
RxFifoOverflow,
- TxFifoUnderflow
+ TxFifoUnderflow,
+ NumSpiDevIntr
} spi_device_intr_e;
typedef enum bit {
diff --git a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
index f16ae1d..4060e25 100644
--- a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
@@ -12,18 +12,17 @@
uvm_tlm_analysis_fifo #(spi_item) device_spi_data_fifo;
// mem model to save expected value
- mem_model tx_mem;
- mem_model rx_mem;
- uint tx_rptr_exp;
- uint rx_wptr_exp;
+ local mem_model tx_mem;
+ local mem_model rx_mem;
+ local uint tx_rptr_exp;
+ local uint rx_wptr_exp;
+
+ // expected values
+ local bit [NumSpiDevIntr-1:0] intr_exp;
// tx/rx fifo, size is 2 words
- bit [31:0] tx_word_fifo[$];
- bit [31:0] rx_word_fifo[$];
-
- // local queues to hold incoming packets pending comparison
- spi_item host_spi_data_q[$];
- spi_item device_spi_data_q[$];
+ local bit [31:0] tx_word_q[$];
+ local bit [31:0] rx_word_q[$];
`uvm_component_new
@@ -124,6 +123,17 @@
update_rx_mem_fifo_and_wptr();
end
end
+ "intr_test": begin
+ if (write && channel == AddrChannel) begin
+ bit [TL_DW-1:0] intr_en = ral.intr_enable.get_mirrored_value();
+ intr_exp |= item.a_data;
+ if (cfg.en_cov) begin
+ foreach (intr_exp[i]) begin
+ cov.intr_test_cg.sample(i, item.a_data[i], intr_en[i], intr_exp[i]);
+ end
+ end
+ end
+ end
// TODO the other regs
endcase
@@ -140,9 +150,9 @@
virtual function void update_tx_fifo_and_rptr();
uint filled_bytes = get_tx_sram_filled_bytes();
// move data to fifo
- while (tx_word_fifo.size < 2 && filled_bytes >= SRAM_WORD_SIZE) begin
- tx_word_fifo.push_back(tx_mem.read(tx_rptr_exp[SRAM_MSB:0]));
- `uvm_info(`gfn, $sformatf("write tx_word_fifo rptr 0x%0h, data: 0x%0h",
+ while (tx_word_q.size < 2 && filled_bytes >= SRAM_WORD_SIZE) begin
+ tx_word_q.push_back(tx_mem.read(tx_rptr_exp[SRAM_MSB:0]));
+ `uvm_info(`gfn, $sformatf("write tx_word_q rptr 0x%0h, data: 0x%0h",
tx_rptr_exp, tx_mem.read(tx_rptr_exp[SRAM_MSB:0])), UVM_MEDIUM)
tx_rptr_exp = get_sram_new_ptr(.ptr(tx_rptr_exp),
.increment(SRAM_WORD_SIZE),
@@ -154,8 +164,8 @@
// send out SPI data from tx_fifo and fetch more data from sram to fifo
virtual function void sendout_spi_tx_data(bit [31:0] data_act);
- if (tx_word_fifo.size > 0) begin
- bit [31:0] data_exp = tx_word_fifo.pop_front();
+ if (tx_word_q.size > 0) begin
+ bit [31:0] data_exp = tx_word_q.pop_front();
`DV_CHECK_EQ(data_act, data_exp, "Compare SPI TX data")
update_tx_fifo_and_rptr();
end else begin // underflow
@@ -167,8 +177,8 @@
// when receive a spi rx data, save it in rx_fifo and then write to rx_mem
// when rx_fifo is full (size=2) and no space in sram, drop it
virtual function void receive_spi_rx_data(bit [TL_DW:0] data);
- if (get_rx_sram_space_bytes() >= SRAM_WORD_SIZE || rx_word_fifo.size < 2) begin
- rx_word_fifo.push_back(data);
+ if (get_rx_sram_space_bytes() >= SRAM_WORD_SIZE || rx_word_q.size < 2) begin
+ rx_word_q.push_back(data);
update_rx_mem_fifo_and_wptr();
end
else begin
@@ -181,8 +191,8 @@
virtual function void update_rx_mem_fifo_and_wptr();
uint space_bytes = get_rx_sram_space_bytes();
// move from fifo to mem
- while (rx_word_fifo.size > 0 && space_bytes >= SRAM_WORD_SIZE) begin
- bit [TL_DW:0] data = rx_word_fifo.pop_front();
+ while (rx_word_q.size > 0 && space_bytes >= SRAM_WORD_SIZE) begin
+ bit [TL_DW:0] data = rx_word_q.pop_front();
rx_mem.write(rx_wptr_exp[SRAM_MSB:0], data);
`uvm_info(`gfn, $sformatf("write rx_mem, addr 0x%0h, data: 0x%0h",
rx_wptr_exp, data), UVM_MEDIUM)
@@ -215,10 +225,15 @@
super.reset(kind);
tx_rptr_exp = ral.txf_ptr.rptr.get_reset();
rx_wptr_exp = ral.rxf_ptr.wptr.get_reset();
+ intr_exp = ral.intr_state.get_reset();
endfunction
function void check_phase(uvm_phase phase);
super.check_phase(phase);
+ `DV_EOT_PRINT_TLM_FIFO_CONTENTS(spi_item, host_spi_data_fifo)
+ `DV_EOT_PRINT_TLM_FIFO_CONTENTS(spi_item, device_spi_data_fifo)
+ `DV_CHECK_EQ(tx_word_q.size, 0)
+ `DV_CHECK_EQ(rx_word_q.size, 0)
endfunction
endclass
diff --git a/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson b/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
index 256fb4b..03696d1 100644
--- a/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
+++ b/hw/ip/spi_device/dv/spi_device_sim_cfg.hjson
@@ -75,6 +75,11 @@
name: spi_device_dummy_item_extra_dly
uvm_test_seq: spi_device_dummy_item_extra_dly_vseq
}
+
+ {
+ name: spi_device_intr
+ uvm_test_seq: spi_device_intr_vseq
+ }
]
// List of regressions.
diff --git a/hw/ip/spi_device/dv/tb/tb.sv b/hw/ip/spi_device/dv/tb/tb.sv
index f16e071..e6bd0c7 100644
--- a/hw/ip/spi_device/dv/tb/tb.sv
+++ b/hw/ip/spi_device/dv/tb/tb.sv
@@ -67,7 +67,7 @@
assign spi_if.miso = miso_en ? miso_o : 1'bz;
assign interrupts[RxFifoFull] = intr_rxf;
- assign interrupts[RxFifoGtLevel] = intr_rxlvl;
+ assign interrupts[RxFifoGeLevel] = intr_rxlvl;
assign interrupts[TxFifoLtLevel] = intr_txlvl;
assign interrupts[RxFwModeErr] = intr_rxerr;
assign interrupts[RxFifoOverflow] = intr_rxoverflow;