[pattgen, dv] Add pattgen_stress_all test

Signed-off-by: Tung Hoang <hoang.tung@wdc.com>
diff --git a/hw/dv/sv/pattgen_agent/pattgen_monitor.sv b/hw/dv/sv/pattgen_agent/pattgen_monitor.sv
index f1e3547..05c1066 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_monitor.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_monitor.sv
@@ -43,6 +43,7 @@
 
     pattgen_item dut_item;
     forever begin
+      wait(cfg.en_monitor);
       dut_item = pattgen_item::type_id::create("dut_item");
       bit_cnt = 0;
       fork
@@ -51,7 +52,7 @@
             // capture pattern bits
             begin
               do begin
-                wait(cfg.en_monitor);
+                wait(cfg.vif.rst_ni);
                 get_pattgen_bit(channel, bit_data);
                 `uvm_info(`gfn, $sformatf("\n--> monitor: channel %0d, polar %b, data[%0d] %b",
                     channel, cfg.polarity[channel], bit_cnt, bit_data), UVM_DEBUG)
@@ -82,6 +83,10 @@
       @(negedge cfg.vif.rst_ni);
       reset_asserted = 1'b1;
       // implement other clean-up actions under reset here
+      for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
+        cfg.error_injected[i]= 1'b0;
+        cfg.length[i] = 0;
+      end
       @(posedge cfg.vif.rst_ni);
       reset_asserted = 1'b0;
     end
diff --git a/hw/ip/pattgen/dv/env/pattgen_channel_cfg.sv b/hw/ip/pattgen/dv/env/pattgen_channel_cfg.sv
index 5051df5..579aba3 100644
--- a/hw/ip/pattgen/dv/env/pattgen_channel_cfg.sv
+++ b/hw/ip/pattgen/dv/env/pattgen_channel_cfg.sv
@@ -16,14 +16,19 @@
   rand bit [5:0]     len;
   rand bit [9:0]     reps;
 
-  // functions
-  virtual function void reset_channel_config();
+  virtual function void reset_channel_config(string kind = "");
     start    = 1'b0;
     stop     = 1'b0;
     enable   = 1'b0;
+    if (kind == "HARD") begin
+      polarity = 1'b0;
+      len      = 0;
+      reps     = 0;
+      prediv   = 0;
+      data     = 0;
+    end
   endfunction : reset_channel_config
 
-  // this function print channel configuration for debug
   virtual function string convert2string();
       string str;
 
@@ -40,4 +45,4 @@
       return str;
   endfunction : convert2string
 
-endclass : pattgen_channel_cfg
\ No newline at end of file
+endclass : pattgen_channel_cfg
diff --git a/hw/ip/pattgen/dv/env/pattgen_env.core b/hw/ip/pattgen/dv/env/pattgen_env.core
index c1734c3..c8d1529 100644
--- a/hw/ip/pattgen/dv/env/pattgen_env.core
+++ b/hw/ip/pattgen/dv/env/pattgen_env.core
@@ -26,6 +26,7 @@
       - seq_lib/pattgen_smoke_vseq.sv: {is_include_file: true}
       - seq_lib/pattgen_perf_vseq.sv: {is_include_file: true}
       - seq_lib/pattgen_error_vseq.sv: {is_include_file: true}
+      - seq_lib/pattgen_stress_all_vseq.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
 generate:
diff --git a/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv b/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv
index e92b22f..2726bbc 100644
--- a/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv
+++ b/hw/ip/pattgen/dv/env/pattgen_scoreboard.sv
@@ -110,8 +110,8 @@
             // channel is operating but incorrectly disabled -> error injected
             if (!channel_cfg[i].enable && channel_cfg[i].start && !channel_cfg[i].stop) begin
               channel_cfg[i].stop = 1'b1;
-              `uvm_info(`gfn, $sformatf("\n  scb: channel %0d is abnormally stopped\n%s",
-                  i, channel_cfg[i].convert2string()), UVM_DEBUG);
+              `uvm_info(`gfn, $sformatf("\n  scb: channel config %0d\n%s",
+                  i, channel_cfg[i].convert2string()), UVM_DEBUG)
               generate_exp_items(.channel(i), .error_injected(1'b1));
             end
           end
@@ -206,7 +206,7 @@
       end else begin
         `uvm_info(`gfn, $sformatf("\n--> scb: drop exp_item for channel %0d", channel), UVM_DEBUG)
       end
-      channel_cfg[channel].reset_channel_config;
+      channel_cfg[channel].reset_channel_config();
     end
   endfunction : generate_exp_items
 
@@ -215,7 +215,7 @@
     for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
       item_fifo[i].flush();
       exp_item_q[i].delete();
-      channel_cfg[i].reset_channel_config();
+      channel_cfg[i].reset_channel_config(kind);
     end
   endfunction : reset
 
diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv
index 602a79e..734407d 100644
--- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv
+++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_base_vseq.sv
@@ -31,7 +31,6 @@
   // if start_all_channels bit is set: both channels can start simmultaneously
   rand bit                            start_all_channels;
   rand bit                            do_error_injected;
-  rand bit [NUM_PATTGEN_CHANNELS-1:0] reset_channels;
 
   // constraints
   constraint num_trans_c {
@@ -91,24 +90,38 @@
     while (num_pattern_req < num_trans ||   // not send all pattern configs
            num_pattern_gen < num_trans ||   // not get  all pattern done interrupts
            channel_start) begin             // at least one channel is running
+      wait(cfg.clk_rst_vif.rst_n); // wait until reset is de-asserted
       fork
-        // all channels are completely independent (programm, start w/ or wo/ sync, and stop)
-        setup_pattgen_channel_0();
-        setup_pattgen_channel_1();
-        start_pattgen_channels();
-        stop_pattgen_channels();
+        begin : isolation_thread
+          fork
+            process_reset();
+            fork
+              // all channels are completely independent (programm, start w/ or wo/ sync, and stop)
+              setup_pattgen_channel_0();
+              setup_pattgen_channel_1();
+              start_pattgen_channels();
+              stop_pattgen_channels();
+            join
+          join_any
+          disable fork;
+        end : isolation_thread
       join
     end
-    `uvm_info(`gfn, $sformatf("\n--> channel_setup %b", channel_setup), UVM_DEBUG)
-    `uvm_info(`gfn, $sformatf("\n--> channel_start %b", channel_start), UVM_DEBUG)
     `uvm_info(`gfn, "\n--> end of sequence", UVM_DEBUG)
   endtask : body
 
-  // TODO: can setup_pattgen_channel task be parameterized?
-  // e.g. index the regster groups of channels before entering while-loop in body task
+  virtual task process_reset();
+    // when reset is asserted, all threads for channels are stopped
+    @(negedge cfg.clk_rst_vif.rst_n);
+    channel_setup = 'h0;
+    channel_start = 'h0;
+    channel_grant = 'h1;
+    `uvm_info(`gfn, "\n  process_reset is called", UVM_DEBUG)
+  endtask : process_reset
+
   virtual task setup_pattgen_channel_0();
     if (num_pattern_req < num_trans &&
-         channel_grant[0] &&       // ch0 setup is granted
+        channel_grant[0] &&       // ch0 setup is granted
         !channel_setup[0] &&       // ch0 has not been programmed
         !channel_start[1]) begin   // ch1 is not under start (avoid re-programming regs)
       wait_for_channel_ready(Channel0);
@@ -296,9 +309,9 @@
         if (status == Enable) begin
           num_pattern_req += 2;
           `uvm_info(`gfn, $sformatf("\n  sync channel 0: request %0d/%0d\n%s",
-              num_pattern_req - 1, num_trans, channel_cfg[0].convert2string()), UVM_DEBUG);
+              num_pattern_req - 1, num_trans, channel_cfg[0].convert2string()), UVM_DEBUG)
           `uvm_info(`gfn, $sformatf("\n  sync channel 1: request %0d/%0d\n%s",
-              num_pattern_req, num_trans, channel_cfg[1].convert2string()), UVM_DEBUG);
+              num_pattern_req, num_trans, channel_cfg[0].convert2string()), UVM_DEBUG)
         end
       end
     endcase
@@ -373,7 +386,6 @@
     x = {x[NUM_PATTGEN_CHANNELS-2:0], x[NUM_PATTGEN_CHANNELS-1]};
   endfunction : right_rotation
 
-  // TODO: this task is reserved for the next PR
   task wait_host_for_idle();
     csr_spinwait(.ptr(ral.ctrl.enable_ch0),     .exp_data(1'b0));
     csr_spinwait(.ptr(ral.ctrl.enable_ch1),     .exp_data(1'b0));
diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv
new file mode 100644
index 0000000..f3ecdd0
--- /dev/null
+++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_stress_all_vseq.sv
@@ -0,0 +1,95 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// combine all pattgen seqs (except below vseqs) in one seq to run sequentially
+// 1. override_vseq requires scb and monitor to be disabled
+// 1. csr seq, which requires scb to be disabled
+class pattgen_stress_all_vseq extends pattgen_base_vseq;
+  `uvm_object_utils(pattgen_stress_all_vseq)
+
+  `uvm_object_new
+
+  local string str, seq_name;
+  local int    seq_run_hist[string];
+
+  string seq_names[] = {
+    "pattgen_common_vseq",      // for intr_test
+    "pattgen_smoke_vseq",
+    "pattgen_perf_vseq",
+    "pattgen_error_vseq"
+  };
+
+  virtual task body();
+
+    `uvm_info(`gfn, "\n=> start pattgen_stress_all_vseq", UVM_LOW)
+    print_seq_names(seq_names);
+    for (int i = 1; i <= seq_names.size(); i++) begin
+      seq_run_hist[seq_names[i-1]] = 0;
+    end
+
+    `DV_CHECK_MEMBER_RANDOMIZE_FATAL(num_runs)
+    for (int i = 1; i <= num_runs; i++) begin
+      uvm_sequence       seq;
+      pattgen_base_vseq  pattgen_vseq;
+      uint               seq_idx = $urandom_range(0, seq_names.size() - 1);
+
+      seq_name = seq_names[seq_idx];
+      `uvm_info(`gfn, $sformatf("\n\n=> start stressing vseq %s (%0d/%0d)",
+          seq_name, i, num_runs), UVM_LOW)
+      seq = create_seq_by_name(seq_name);
+      `downcast(pattgen_vseq, seq)
+
+      // if upper seq disables do_apply_reset for this seq, then can't issue reset
+      // as upper seq may drive reset
+      if (do_apply_reset) begin
+        pattgen_vseq.do_apply_reset = $urandom_range(0, 1);
+        if (pattgen_vseq.do_apply_reset) begin
+          `uvm_info(`gfn, "\n  *reset is randomly issued with stress_test", UVM_LOW)
+        end
+      end else begin
+        pattgen_vseq.do_apply_reset = 0;
+        `uvm_info(`gfn, "\n  *upper_seq may drive reset thus not issue reset", UVM_DEBUG)
+      end
+
+      pattgen_vseq.set_sequencer(p_sequencer);
+      `DV_CHECK_RANDOMIZE_FATAL(pattgen_vseq)
+      case (seq_name)
+        "pattgen_common_vseq": begin
+          pattgen_common_vseq common_vseq;
+          `downcast(common_vseq, pattgen_vseq);
+          common_vseq.common_seq_type = "intr_test";
+          cfg.en_scb = 1'b0;
+        end
+        default: begin
+          cfg.en_scb = 1'b1;
+        end
+      endcase
+      // run vseq
+      pattgen_vseq.start(p_sequencer);
+      seq_run_hist[seq_name]++;
+      `uvm_info(`gfn, $sformatf("\n  end stressing vseq %s", seq_name), UVM_LOW)
+    end
+    wait_host_for_idle();
+    `uvm_info(`gfn, "\n=> end of pattgen_stress_all_vseq", UVM_LOW)
+
+    // get the histogram of vseq running
+    str = {str, "\n\n=> vseq run histogram:"};
+    for (int i = 0; i < seq_names.size(); i++) begin
+      seq_name = seq_names[i];
+      str = {str, $sformatf("\n  %-25s  %2d / %2d", seq_name, seq_run_hist[seq_name], num_runs)};
+    end
+    `uvm_info(`gfn, $sformatf("%s\n", str), UVM_LOW)
+  endtask : body
+
+  virtual function void print_seq_names(const ref string seq_names[]);
+    string str;
+
+    `uvm_info(`gfn, $sformatf("\n  list of %0d vseqs are stressed", seq_names.size()), UVM_LOW)
+    for (int i = 1; i <= seq_names.size(); i++) begin
+      str = {str, $sformatf("\n    %s", seq_names[i-1])};
+    end
+    `uvm_info(`gfn, $sformatf("%s", str), UVM_LOW)
+  endfunction : print_seq_names
+
+endclass : pattgen_stress_all_vseq
diff --git a/hw/ip/pattgen/dv/env/seq_lib/pattgen_vseq_list.sv b/hw/ip/pattgen/dv/env/seq_lib/pattgen_vseq_list.sv
index 239d136..39a9e9b 100644
--- a/hw/ip/pattgen/dv/env/seq_lib/pattgen_vseq_list.sv
+++ b/hw/ip/pattgen/dv/env/seq_lib/pattgen_vseq_list.sv
@@ -7,3 +7,4 @@
 `include "pattgen_smoke_vseq.sv"
 `include "pattgen_perf_vseq.sv"
 `include "pattgen_error_vseq.sv"
+`include "pattgen_stress_all_vseq.sv"