[spi_device, dv] Refactor spi_agent to support spi_host rtl
- Extend spi_if to provide 4 channels required by spi_host rtl
- Replace uni-direction sdi and sdo ports by bi-direction sio ports in spi_if
- Update spi_device and top_earlgrey testbench with new ports
Signed-off-by: Tung Hoang <hoang.tung@wdc.com>
diff --git a/hw/dv/sv/spi_agent/spi_agent_cfg.sv b/hw/dv/sv/spi_agent/spi_agent_cfg.sv
index e593d93..fbac367 100644
--- a/hw/dv/sv/spi_agent/spi_agent_cfg.sv
+++ b/hw/dv/sv/spi_agent/spi_agent_cfg.sv
@@ -4,19 +4,22 @@
class spi_agent_cfg extends dv_base_agent_cfg;
- // agent cfg knobs
- bit en_monitor_collect_trans = 1'b1; // enable monitor to collect trans on-the-fly
- bit en_monitor_checks = 1'b1; // enable checkers in monitor
+ // enable checkers in monitor
+ bit en_monitor_checks = 1'b1;
// host mode cfg knobs
- time sck_period_ps = 50_000; // 20MHz
- bit sck_polarity; // aka CPOL
- bit sck_phase; // aka CPHA
- bit host_bit_dir; // 1 - lsb -> msb, 0 - msb -> lsb
- bit device_bit_dir; // 1 - lsb -> msb, 0 - msb -> lsb
- bit sck_on; // keep sck on
+ time sck_period_ps = 50_000; // 20MHz
+ bit sck_polarity; // aka CPOL
+ bit sck_phase; // aka CPHA
+ bit host_bit_dir; // 1 - lsb -> msb, 0 - msb -> lsb
+ bit device_bit_dir; // 1 - lsb -> msb, 0 - msb -> lsb
+ bit sck_on; // keep sck on
+
+ // spi mode knob
+ spi_mode_e spi_mode;
+
// how many bytes monitor samples per transaction
- int num_bytes_per_trans_in_mon = 4;
+ int num_bytes_per_trans_in_mon = 4;
// enable randomly injecting extra delay between 2 sck/word
bit en_extra_dly_btw_sck;
@@ -31,20 +34,21 @@
uint extra_dly_chance_pc_btw_word = 5; // percentage of extra delay btw each word
// interface handle used by driver, monitor & the sequencer
- virtual spi_if vif;
+ virtual spi_if vif;
`uvm_object_utils_begin(spi_agent_cfg)
- `uvm_field_int (sck_period_ps, UVM_DEFAULT)
- `uvm_field_int (sck_polarity, UVM_DEFAULT)
- `uvm_field_int (sck_phase, UVM_DEFAULT)
- `uvm_field_int (host_bit_dir, UVM_DEFAULT)
- `uvm_field_int (device_bit_dir, UVM_DEFAULT)
+ `uvm_field_int (sck_period_ps, UVM_DEFAULT)
+ `uvm_field_int (sck_polarity, UVM_DEFAULT)
+ `uvm_field_int (sck_phase, UVM_DEFAULT)
+ `uvm_field_int (host_bit_dir, UVM_DEFAULT)
+ `uvm_field_int (device_bit_dir, UVM_DEFAULT)
`uvm_field_int (en_extra_dly_btw_sck, UVM_DEFAULT)
`uvm_field_int (max_extra_dly_ns_btw_sck, UVM_DEFAULT)
`uvm_field_int (extra_dly_chance_pc_btw_sck, UVM_DEFAULT)
`uvm_field_int (en_extra_dly_btw_word, UVM_DEFAULT)
`uvm_field_int (max_extra_dly_ns_btw_word, UVM_DEFAULT)
`uvm_field_int (extra_dly_chance_pc_btw_word, UVM_DEFAULT)
+ `uvm_field_enum(spi_mode_e, spi_mode, UVM_DEFAULT)
`uvm_object_utils_end
`uvm_object_new
@@ -72,4 +76,4 @@
else @(negedge vif.sck);
endtask
-endclass
+endclass : spi_agent_cfg
diff --git a/hw/dv/sv/spi_agent/spi_agent_pkg.sv b/hw/dv/sv/spi_agent/spi_agent_pkg.sv
index f1bc2b4..7f34c99 100644
--- a/hw/dv/sv/spi_agent/spi_agent_pkg.sv
+++ b/hw/dv/sv/spi_agent/spi_agent_pkg.sv
@@ -27,6 +27,13 @@
SamplingEdge
} sck_edge_type_e;
+ // spi mode
+ typedef enum {
+ Single = 0, // Full duplex, tx: sio[0], rx: sio[1]
+ Dual = 1, // Half duplex, tx and rx: sio[1:0]
+ Quad = 2 // Half duplex, tx and rx: sio[3:0]
+ } spi_mode_e;
+
// functions
// package sources
diff --git a/hw/dv/sv/spi_agent/spi_device_driver.sv b/hw/dv/sv/spi_agent/spi_device_driver.sv
index f1684f5..48c1f27 100644
--- a/hw/dv/sv/spi_agent/spi_device_driver.sv
+++ b/hw/dv/sv/spi_agent/spi_device_driver.sv
@@ -10,7 +10,7 @@
forever begin
@(negedge cfg.vif.rst_n);
under_reset = 1'b1;
- cfg.vif.sdo <= 1'b0;
+ cfg.vif.sio <= 'hz;
@(posedge cfg.vif.rst_n);
under_reset = 1'b0;
end
diff --git a/hw/dv/sv/spi_agent/spi_host_driver.sv b/hw/dv/sv/spi_agent/spi_host_driver.sv
index 6263214..ca618ce 100644
--- a/hw/dv/sv/spi_agent/spi_host_driver.sv
+++ b/hw/dv/sv/spi_agent/spi_host_driver.sv
@@ -21,8 +21,8 @@
@(negedge cfg.vif.rst_n);
under_reset = 1'b1;
cfg.vif.sck <= cfg.sck_polarity;
- cfg.vif.csb <= 1'b1;
- cfg.vif.sdi <= 1'bx;
+ cfg.vif.csb <= 'hf;
+ cfg.vif.sio <= 'hz;
sck_pulses = 0;
@(posedge cfg.vif.rst_n);
under_reset = 1'b0;
@@ -80,7 +80,7 @@
endtask
task drive_normal_item();
- cfg.vif.csb <= 1'b0;
+ cfg.vif.csb[0] <= 1'b0;
sck_pulses = req.data.size() * 8;
// for mode 1 and 3, get the leading edges out of the way
@@ -93,13 +93,13 @@
int which_bit;
host_byte = req.data[i];
for (int j = 0; j < 8; j++) begin
- // drive sdi early so that it is stable at the sampling edge
+ // drive sio early so that it is stable at the sampling edge
which_bit = cfg.host_bit_dir ? j : 7 - j;
- cfg.vif.sdi <= host_byte[which_bit];
- // wait for sampling edge to sample sdo (half cycle)
+ cfg.vif.sio[0] <= host_byte[which_bit];
+ // wait for sampling edge to sample sio (half cycle)
cfg.wait_sck_edge(SamplingEdge);
which_bit = cfg.device_bit_dir ? j : 7 - j;
- device_byte[which_bit] = cfg.vif.sdo;
+ device_byte[which_bit] = cfg.vif.sio[1];
// wait for driving edge to complete 1 cycle
if (i != req.data.size() - 1 || j != 7) cfg.wait_sck_edge(DrivingEdge);
end
@@ -107,8 +107,8 @@
end
wait(sck_pulses == 0);
- cfg.vif.csb <= 1'b1;
- cfg.vif.sdi <= 1'bx;
+ cfg.vif.csb[0] <= 1'b1;
+ cfg.vif.sio[0] <= 1'bx;
endtask
task drive_sck_no_csb_item();
@@ -121,9 +121,9 @@
endtask
task drive_csb_no_sck_item();
- cfg.vif.csb <= 1'b0;
+ cfg.vif.csb[0] <= 1'b0;
#(req.dummy_sck_length_ns * 1ns);
- cfg.vif.csb <= 1'b1;
+ cfg.vif.csb[0] <= 1'b1;
endtask
function uint get_rand_extra_delay_ns_btw_sck();
diff --git a/hw/dv/sv/spi_agent/spi_if.sv b/hw/dv/sv/spi_agent/spi_if.sv
index 06a23b4..562f011 100644
--- a/hw/dv/sv/spi_agent/spi_if.sv
+++ b/hw/dv/sv/spi_agent/spi_if.sv
@@ -2,13 +2,14 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-interface spi_if (input rst_n);
+interface spi_if (
+ input rst_n
+);
// standard spi interface pins
- logic sck;
- logic csb;
- logic sdo;
- logic sdi;
+ logic sck;
+ logic [3:0] csb;
+ logic [3:0] sio;
// debug signals
logic [7:0] host_byte;
@@ -19,4 +20,4 @@
bit sck_polarity;
bit sck_phase;
-endinterface
+endinterface : spi_if
diff --git a/hw/dv/sv/spi_agent/spi_monitor.sv b/hw/dv/sv/spi_agent/spi_monitor.sv
index 8d47573..81b6ab1 100644
--- a/hw/dv/sv/spi_agent/spi_monitor.sv
+++ b/hw/dv/sv/spi_agent/spi_monitor.sv
@@ -20,7 +20,7 @@
function void build_phase(uvm_phase phase);
super.build_phase(phase);
- host_analysis_port = new("host_analysis_port", this);
+ host_analysis_port = new("host_analysis_port", this);
device_analysis_port = new("device_analysis_port", this);
endfunction
@@ -35,43 +35,40 @@
forever begin
@(negedge cfg.vif.csb);
- if (cfg.en_monitor_collect_trans) collect_curr_trans();
+ collect_curr_trans();
end
- endtask
+ endtask : collect_trans
virtual protected task collect_curr_trans();
-
fork
begin: isolation_thread
fork
begin: csb_deassert_thread
- wait(cfg.vif.csb == 1'b1);
+ wait(cfg.vif.csb[0] == 1'b1);
end
begin: sample_thread
// for mode 1 and 3, get the leading edges out of the way
cfg.wait_sck_edge(LeadingEdge);
forever begin
- bit [7:0] host_byte; // from sdi
- bit [7:0] device_byte; // from sdo
+ bit [7:0] host_byte; // from sio
+ bit [7:0] device_byte; // from sio
int which_bit;
for (int i = 0; i < 8; i++) begin
// wait for the sampling edge
cfg.wait_sck_edge(SamplingEdge);
- // check sdi/sdo not x or z
+ // check sio not x or z
if (cfg.en_monitor_checks) begin
- `DV_CHECK_CASE_NE(cfg.vif.sdi, 1'bx)
- `DV_CHECK_CASE_NE(cfg.vif.sdi, 1'bz)
- `DV_CHECK_CASE_NE(cfg.vif.sdo, 1'bx)
- `DV_CHECK_CASE_NE(cfg.vif.sdo, 1'bz)
+ `DV_CHECK_CASE_NE(cfg.vif.sio[1:0], 2'bxx)
+ `DV_CHECK_CASE_NE(cfg.vif.sio[1:0], 2'bxx)
end
- // sample sdi
+ // sample sio[0] for tx
which_bit = cfg.host_bit_dir ? i : 7 - i;
- host_byte[which_bit] = cfg.vif.sdi;
- cfg.vif.host_bit = which_bit;
+ host_byte[which_bit] = cfg.vif.sio[0];
+ cfg.vif.host_bit = which_bit;
cfg.vif.host_byte = host_byte;
- // sample sdo
+ // sample sio[1] for rx
which_bit = cfg.device_bit_dir ? i : 7 - i;
- device_byte[which_bit] = cfg.vif.sdo;
+ device_byte[which_bit] = cfg.vif.sio[1];
cfg.vif.device_bit = which_bit;
cfg.vif.device_byte = device_byte;
end
@@ -96,13 +93,13 @@
disable fork;
end
join
- endtask
+ endtask : collect_curr_trans
virtual task monitor_ready_to_end();
forever begin
@(cfg.vif.csb);
ok_to_end = !cfg.vif.csb;
end
- endtask
+ endtask : monitor_ready_to_end
-endclass
+endclass : spi_monitor
diff --git a/hw/dv/sv/spi_agent/spi_sequencer.sv b/hw/dv/sv/spi_agent/spi_sequencer.sv
index b835891..62017f8 100644
--- a/hw/dv/sv/spi_agent/spi_sequencer.sv
+++ b/hw/dv/sv/spi_agent/spi_sequencer.sv
@@ -7,4 +7,4 @@
`uvm_component_new
-endclass
+endclass : spi_sequencer
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 3a90ae3..a849fe5 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
@@ -105,8 +105,8 @@
endtask
// NOTE on terminology
- // from spi_device IP perspective, tx is data sent out over sdo (device traffic from the IP),
- // rx is data received over sdi (host traffic from SPI agent)
+ // from spi_device IP perspective, tx is data sent out over sio[0] (device traffic from the IP),
+ // rx is data received over sio[1] (host traffic from SPI agent)
// TODO: use spi_device_pkg spi_mode enum instead
virtual task spi_device_init();
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 2c99f9d..a84f555 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
@@ -10,7 +10,7 @@
virtual task body();
allow_underflow_overflow = 1;
- // when underflow, sdo may be unknown, disable checking it
+ // when underflow, sio may be unknown, disable checking it
cfg.m_spi_agent_cfg.en_monitor_checks = 0;
super.body();
cfg.m_spi_agent_cfg.en_monitor_checks = 1;
diff --git a/hw/ip/spi_device/dv/tb/tb.sv b/hw/ip/spi_device/dv/tb/tb.sv
index 1503af3..302184d 100644
--- a/hw/ip/spi_device/dv/tb/tb.sv
+++ b/hw/ip/spi_device/dv/tb/tb.sv
@@ -33,10 +33,10 @@
// interfaces
clk_rst_if clk_rst_if(.clk(clk), .rst_n(rst_n));
+ tl_if tl_if(.clk(clk), .rst_n(rst_n));
pins_if #(NUM_MAX_INTERRUPTS) intr_if(.pins(interrupts));
pins_if #(1) devmode_if(devmode);
- tl_if tl_if(.clk(clk), .rst_n(rst_n));
- spi_if spi_if(.rst_n(rst_n));
+ spi_if spi_if(.rst_n(rst_n));
// dut
spi_device dut (
@@ -61,11 +61,11 @@
.scanmode_i (lc_ctrl_pkg::Off)
);
- assign sck = spi_if.sck;
- assign csb = spi_if.csb;
+ assign sck = spi_if.sck;
+ assign csb = spi_if.csb[0];
// TODO: quad SPI mode is currently not yet implemented
- assign sd_in = {3'b000, spi_if.sdi};
- assign spi_if.sdo = sd_out_en[1] ? sd_out[1] : 1'bz;
+ assign sd_in = {3'b000, spi_if.sio[0]};
+ assign spi_if.sio[1] = sd_out_en[1] ? sd_out[1] : 1'bz;
assign interrupts[RxFifoFull] = intr_rxf;
assign interrupts[RxFifoGeLevel] = intr_rxlvl;
diff --git a/hw/top_earlgrey/dv/tb/tb.sv b/hw/top_earlgrey/dv/tb/tb.sv
index 4c53732..0151b6e 100644
--- a/hw/top_earlgrey/dv/tb/tb.sv
+++ b/hw/top_earlgrey/dv/tb/tb.sv
@@ -180,8 +180,8 @@
assign spi_device_sck = spi_if.sck;
assign spi_device_csb = spi_if.csb;
- assign spi_device_sdi_i = spi_if.sdi;
- assign spi_if.sdo = spi_device_sdo_o;
+ assign spi_device_sdi_i = spi_if.sio[0];
+ assign spi_if.sio[1] = spi_device_sdo_o;
// TODO: Replace this weak pull to a known value with initialization
// in the agent/interface.