[spi_host/dv] Enhanced Smoke Test

- Added Speed Test
- Added Constraints to Segment Item
- Added Quad And Dual To Device Resp Seq
- Added Tag For Cover Points To Speed Test

Signed-off-by: Viswanadha Bazawada <viswanadha.bazawada@ensilica.com>
diff --git a/hw/dv/sv/spi_agent/seq_lib/spi_device_cmd_rsp_seq.sv b/hw/dv/sv/spi_agent/seq_lib/spi_device_cmd_rsp_seq.sv
index 02e376b..7ffa4c7 100644
--- a/hw/dv/sv/spi_agent/seq_lib/spi_device_cmd_rsp_seq.sv
+++ b/hw/dv/sv/spi_agent/seq_lib/spi_device_cmd_rsp_seq.sv
@@ -78,7 +78,7 @@
 
         SpiData: begin
           case (cmd)
-            ReadStd: begin
+            ReadStd, ReadDual, ReadQuad: begin
               // read_until CSB low
               data = $urandom();
               addr_cnt += 4;
@@ -100,7 +100,7 @@
               end
             end
 
-            WriteStd: begin
+            WriteStd, WriteDual, WriteQuad: begin
               get_nxt_req(item);
               if (item.first_byte) begin
                 // decode command
diff --git a/hw/ip/spi_host/data/spi_host_testplan.hjson b/hw/ip/spi_host/data/spi_host_testplan.hjson
index 9d49fbf..61a7469 100644
--- a/hw/ip/spi_host/data/spi_host_testplan.hjson
+++ b/hw/ip/spi_host/data/spi_host_testplan.hjson
@@ -77,7 +77,7 @@
               - verify that the DUT can handle different sck -> cs_n timings
             '''
       milestone: V2
-      tests: []
+      tests: ["spi_host_speed"]
     }
     {
       name: speed
@@ -89,7 +89,7 @@
               - verify that all speeds are supported
             '''
       milestone: V2
-      tests: []
+      tests: ["spi_host_speed"]
     }
     {
       name: chip_select_timing
@@ -101,7 +101,7 @@
               - Check that the DUT operates correctly under different SPI clock speeds
             '''
       milestone: V2
-      tests: []
+      tests: ["spi_host_speed"]
     }
     {
       name: sw_reset
@@ -143,7 +143,7 @@
               - Check that the DUT operates correctly under different cs_n settings
             '''
       milestone: V2
-      tests: []
+      tests: ["spi_host_speed"]
     }
     {
       name: full_cycle
diff --git a/hw/ip/spi_host/dv/env/seq_lib/spi_host_smoke_vseq.sv b/hw/ip/spi_host/dv/env/seq_lib/spi_host_smoke_vseq.sv
index 70fce53..5cce96f 100644
--- a/hw/ip/spi_host/dv/env/seq_lib/spi_host_smoke_vseq.sv
+++ b/hw/ip/spi_host/dv/env/seq_lib/spi_host_smoke_vseq.sv
@@ -7,21 +7,26 @@
   `uvm_object_utils(spi_host_smoke_vseq)
   `uvm_object_new
 
-    int   num_transactions = 2;
-
   virtual task body();
     fork
-      begin: isolation_fork
+      begin : isolation_fork
         fork
           start_reactive_seq();
         join_none
 
-        wait_ready_for_command();
-        start_spi_host_trans(num_transactions);
-        read_rx_fifo();
+        begin
+          wait_ready_for_command();
+          start_spi_host_trans(num_trans);
+          csr_spinwait(.ptr(ral.status.active), .exp_data(1'b0));
+          csr_spinwait(.ptr(ral.status.rxqd), .exp_data(8'h0));
+          cfg.clk_rst_vif.wait_clks(100);
+        end
 
         disable fork;
       end
+      begin
+        read_rx_fifo();
+      end
     join
   endtask : body
 
diff --git a/hw/ip/spi_host/dv/env/seq_lib/spi_host_speed_vseq.sv b/hw/ip/spi_host/dv/env/seq_lib/spi_host_speed_vseq.sv
new file mode 100644
index 0000000..d241442
--- /dev/null
+++ b/hw/ip/spi_host/dv/env/seq_lib/spi_host_speed_vseq.sv
@@ -0,0 +1,21 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// speed test vseq
+class spi_host_speed_vseq extends spi_host_smoke_vseq;
+  `uvm_object_utils(spi_host_speed_vseq)
+  `uvm_object_new
+
+  int num_transactions = 2;
+
+  virtual task start_spi_host_trans(int num_transactions);
+    cfg.seq_cfg.std_en  = 1;
+    cfg.seq_cfg.dual_en = 1;
+    //TODO: enable quad_en
+    cfg.seq_cfg.quad_en = 0;
+    super.start_spi_host_trans(num_transactions);
+  endtask
+
+endclass : spi_host_speed_vseq
+
diff --git a/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv b/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv
index f969594..3e9737c 100644
--- a/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv
+++ b/hw/ip/spi_host/dv/env/seq_lib/spi_host_tx_rx_vseq.sv
@@ -26,26 +26,33 @@
     cfg.seq_cfg.host_spi_min_len = 4;
     cfg.seq_cfg.host_spi_max_len = 16;
 
-    for(int n = 0; n < num_transactions; n++) begin
+    for (int n = 0; n < num_transactions; n++) begin
       generate_transaction();
       send_trans(transaction);
-      cfg.clk_rst_vif.wait_clks(100);
+      wait_ready_for_command();
     end
   endtask
 
 
   virtual task read_rx_fifo();
-    bit [7:0] fifo_entries = 0;
     bit [7:0] read_q[$];
+    bit active = 0;
+    bit rxempty;
+    spi_host_status_t status;
 
-    csr_rd(.ptr(ral.status.rxqd), .value(fifo_entries));
-    do begin
-      for(int i = 0; i <fifo_entries; i++) begin
-        access_data_fifo(read_q, RxFifo);
+    csr_spinwait(.ptr(ral.status.active), .exp_data(1'b1));
+    csr_spinwait(.ptr(ral.status.rxempty), .exp_data(1'b0));
+    forever begin
+      do begin
+        csr_rd(.ptr(ral.status), .value(status));
+        for (int i = 0; i < status.rx_qd; i++) begin
+          access_data_fifo(read_q, RxFifo);
+        end
+      end while (status.rx_qd > 0);
+      if (!status.active && status.rxempty && (status.rx_qd == 0)) begin
+        break;
       end
-      csr_spinwait(.ptr(ral.status.active), .exp_data(1'b0));
-      csr_rd(.ptr(ral.status.rxqd), .value(fifo_entries));
-    end while (fifo_entries > 0 );
+    end  // forever loop
 
     // wait for all accesses to complete
     wait_no_outstanding_access();
@@ -65,7 +72,7 @@
       // lock fifo to this seq
       spi_host_atomic.get(1);
       // write data to fifo
-      if(segment.command_reg.direction  != RxOnly) begin
+      if (segment.command_reg.direction != RxOnly) begin
         access_data_fifo(segment.spi_data, TxFifo);
       end
       program_command_reg(segment.command_reg);
diff --git a/hw/ip/spi_host/dv/env/seq_lib/spi_host_vseq_list.sv b/hw/ip/spi_host/dv/env/seq_lib/spi_host_vseq_list.sv
index 80c1683..b738552 100644
--- a/hw/ip/spi_host/dv/env/seq_lib/spi_host_vseq_list.sv
+++ b/hw/ip/spi_host/dv/env/seq_lib/spi_host_vseq_list.sv
@@ -5,4 +5,5 @@
 `include "spi_host_base_vseq.sv"
 `include "spi_host_tx_rx_vseq.sv"
 `include "spi_host_smoke_vseq.sv"
+`include "spi_host_speed_vseq.sv"
 `include "spi_host_common_vseq.sv"
diff --git a/hw/ip/spi_host/dv/env/spi_host_env.core b/hw/ip/spi_host/dv/env/spi_host_env.core
index b95abb1..1cd803e 100644
--- a/hw/ip/spi_host/dv/env/spi_host_env.core
+++ b/hw/ip/spi_host/dv/env/spi_host_env.core
@@ -26,6 +26,7 @@
       - seq_lib/spi_host_tx_rx_vseq.sv: {is_include_file: true}
       - seq_lib/spi_host_common_vseq.sv: {is_include_file: true}
       - seq_lib/spi_host_smoke_vseq.sv: {is_include_file: true}
+      - seq_lib/spi_host_speed_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
 generate:
diff --git a/hw/ip/spi_host/dv/env/spi_segment_item.sv b/hw/ip/spi_host/dv/env/spi_segment_item.sv
index c88c3bf..ac5ee3d 100644
--- a/hw/ip/spi_host/dv/env/spi_segment_item.sv
+++ b/hw/ip/spi_host/dv/env/spi_segment_item.sv
@@ -18,79 +18,110 @@
   // i.e the rx setting does not affect
   // the tx distribution
   // for the use the knob for the cmd
-  int  rx_only_weight                 = 20;
-  int  tx_only_weight                 = 20;
-  int  dummy_weight                   = 0;
+  int                           rx_only_weight     = 20;
+  int                           tx_only_weight     = 20;
+  int                           dummy_weight       = 0;
 
   // num dummy cycles
-  int num_dummy                       = 0;
+  int                           num_dummy          = 0;
   //num_addr_bytes
-  int num_cmd_bytes                   = 4;
+  int                           num_cmd_bytes      = 4;
 
   // transaction len
-  int  spi_len_min = 2;
-  int  spi_len_max = 4;
+  int                           spi_len_min        = 2;
+  int                           spi_len_max        = 4;
 
-  spi_cmd_e              cmd;
-  spi_segment_type_e     seg_type     = Data;
-  rand spi_host_command_t command_reg;
-  rand bit [7:0] spi_data[$];
+  spi_cmd_e                     cmd;
+  spi_segment_type_e            seg_type           = Data;
+  rand spi_host_command_t       command_reg;
+  rand bit                [7:0] spi_data      [$];
 
   constraint command_reg_c {
     //make sure the direction matches the segtype /cmd address are always tx/standard
-    if ( (cmd inside {ReadStd, ReadDual, ReadQuad}) && (seg_type inside {Dummy, Data}) ) {
-      command_reg.direction dist { RxOnly := rx_only_weight,
-                                   None   := dummy_weight/2,
-                                   Bidir  := 100 - (rx_only_weight + dummy_weight)};
+    if ((cmd inside {ReadStd}) && (seg_type inside {Dummy, Data})) {
+      command_reg.direction dist {
+        RxOnly := rx_only_weight,
+        None   := dummy_weight / 2,
+        Bidir  := 100 - (rx_only_weight + dummy_weight)
+      };
+    } else
+    if ((cmd inside {ReadDual, ReadQuad}) && (seg_type inside {Dummy, Data})) {
+      command_reg.direction dist {
+        RxOnly := rx_only_weight,
+        None   := dummy_weight / 2
+      };
+    } else
+    if ((cmd inside {WriteDual, WriteQuad}) && (seg_type inside {Dummy, Data})) {
+      command_reg.direction dist {
+        TxOnly := tx_only_weight,
+        None   := dummy_weight / 2
+      };
     } else {
-      command_reg.direction dist { TxOnly := tx_only_weight,
-                                   None   := dummy_weight/2,
-                                   Bidir  := 100 - (tx_only_weight + dummy_weight)};
+      command_reg.direction dist {
+        TxOnly := tx_only_weight,
+        None   := dummy_weight / 2,
+        Bidir  := 100 - (tx_only_weight + dummy_weight)
+      };
     }
 
 
     if (seg_type == Command) {
       command_reg.mode == Standard;
     } else {
-      if      (cmd inside {ReadStd, WriteStd})   { command_reg.mode == Standard; }
-      else if (cmd inside {ReadDual, WriteDual}) { command_reg.mode == Dual; }
-      else                                       { command_reg.mode == Quad; }
+      if (cmd inside {ReadStd, WriteStd}) {
+        command_reg.mode == Standard;
+      } else
+      if (cmd inside {ReadDual, WriteDual}) {
+        command_reg.mode == Dual;
+      } else {
+        command_reg.mode == Quad;
+      }
     }
 
-    if      (seg_type == Command) { command_reg.len == num_cmd_bytes-1; }
-    else if (seg_type == Dummy  ) { command_reg.len == num_dummy-1; }
-    else {   command_reg.len inside  { [spi_len_min-1:spi_len_max-1]}; }
+    if (seg_type == Command) {
+      command_reg.len == num_cmd_bytes - 1;
+    } else
+    if (seg_type == Dummy) {
+      command_reg.len == num_dummy - 1;
+    } else {
+      command_reg.len inside {[spi_len_min - 1 : spi_len_max - 1]};
+    }
 
     // ensure we only half or full word writes
-    (command_reg.len+1)%2 == 0;
+    (command_reg.len + 1) % 2 == 0;
     // default set keep transaction going
     command_reg.csaat == 1;
   }
 
   constraint data_c {
-    if      (seg_type == Command)  { spi_data.size() == num_cmd_bytes; }
-    else if (seg_type == Dummy)    { spi_data.size() == num_dummy; }
-    else                           { spi_data.size() == command_reg.len+1; }
+    if (seg_type == Command) {
+      spi_data.size() == num_cmd_bytes;
+    } else
+    if (seg_type == Dummy) {
+      spi_data.size() == num_dummy;
+    } else {
+      spi_data.size() == command_reg.len + 1;
+    }
 
     solve command_reg.len before spi_data;
   }
 
 
-  virtual function void do_copy( uvm_object rhs);
+  virtual function void do_copy(uvm_object rhs);
     spi_segment_item rhs_;
     `downcast(rhs_, rhs);
     super.do_copy(rhs);
-    cmd                    =    rhs_.cmd;
-    rx_only_weight         =    rhs_.rx_only_weight;
-    tx_only_weight         =    rhs_.tx_only_weight;
-    num_dummy              =    rhs_.num_dummy;
-    num_cmd_bytes          =    rhs_.num_cmd_bytes;
-    seg_type               =    rhs_.seg_type;
-    command_reg.csaat      =    rhs_.command_reg.csaat;
-    command_reg.direction  =    rhs_.command_reg.direction;
-    command_reg.mode       =    rhs_.command_reg.mode;
-    command_reg.len        =    rhs_.command_reg.len;
-    spi_data               =    rhs_.spi_data;
+    cmd                   = rhs_.cmd;
+    rx_only_weight        = rhs_.rx_only_weight;
+    tx_only_weight        = rhs_.tx_only_weight;
+    num_dummy             = rhs_.num_dummy;
+    num_cmd_bytes         = rhs_.num_cmd_bytes;
+    seg_type              = rhs_.seg_type;
+    command_reg.csaat     = rhs_.command_reg.csaat;
+    command_reg.direction = rhs_.command_reg.direction;
+    command_reg.mode      = rhs_.command_reg.mode;
+    command_reg.len       = rhs_.command_reg.len;
+    spi_data              = rhs_.spi_data;
   endfunction
 
 
@@ -102,17 +133,17 @@
 
 
   function string convert2string();
-    string txt ="";
+    string txt = "";
 
     txt = {txt, $sformatf("\n ----| Command Register |----")};
     txt = {txt, $sformatf("\n ----| Command: %s", cmd.name)};
     txt = {txt, $sformatf("\n ----| Segment %s", seg_type.name)};
     txt = {txt, $sformatf("\n ----| Length: %d", command_reg.len)};
-    txt = {txt, $sformatf("\n ----| Mode: %s",   command_reg.mode.name )};
-    txt = {txt, $sformatf("\n ----| CSAAT: %d",  command_reg.csaat )};
-    txt = {txt, $sformatf("\n ----| Direction: %s", command_reg.direction.name )};
+    txt = {txt, $sformatf("\n ----| Mode: %s", command_reg.mode.name)};
+    txt = {txt, $sformatf("\n ----| CSAAT: %d", command_reg.csaat)};
+    txt = {txt, $sformatf("\n ----| Direction: %s", command_reg.direction.name)};
     txt = {txt, $sformatf("\n ----| DATA |----")};
-    foreach ( spi_data[i]) begin
+    foreach (spi_data[i]) begin
       txt = {txt, $sformatf("\n ----| [%d] %2h |----", i, spi_data[i])};
     end
     return txt;
diff --git a/hw/ip/spi_host/dv/spi_host_sim_cfg.hjson b/hw/ip/spi_host/dv/spi_host_sim_cfg.hjson
index 90bc694..fb8569e 100644
--- a/hw/ip/spi_host/dv/spi_host_sim_cfg.hjson
+++ b/hw/ip/spi_host/dv/spi_host_sim_cfg.hjson
@@ -68,6 +68,10 @@
       name: spi_host_smoke
       uvm_test_seq: spi_host_smoke_vseq
     }
+    {
+      name: spi_host_speed
+      uvm_test_seq: spi_host_speed_vseq
+    }
     // TODO: add more tests here
   ]