[pattgen, dv] Parameterize pattgen_agent

Signed-off-by: Tung Hoang <hoang.tung@wdc.com>
diff --git a/hw/dv/sv/pattgen_agent/pattgen_agent.core b/hw/dv/sv/pattgen_agent/pattgen_agent.core
index 5e7edfa..968d806 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_agent.core
+++ b/hw/dv/sv/pattgen_agent/pattgen_agent.core
@@ -13,13 +13,10 @@
       - pattgen_agent_pkg.sv
       - pattgen_if.sv
       - pattgen_item.sv: {is_include_file: true}
-      - pattgen_host_driver.sv: {is_include_file: true}
-      - pattgen_device_driver.sv: {is_include_file: true}
       - pattgen_driver.sv: {is_include_file: true}
       - pattgen_agent_cfg.sv: {is_include_file: true}
       - pattgen_agent_cov.sv: {is_include_file: true}
       - pattgen_monitor.sv: {is_include_file: true}
-      - pattgen_sequencer.sv: {is_include_file: true}
       - pattgen_agent.sv: {is_include_file: true}
     file_type: systemVerilogSource
 
diff --git a/hw/dv/sv/pattgen_agent/pattgen_agent.sv b/hw/dv/sv/pattgen_agent/pattgen_agent.sv
index b929ee1..2528700 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_agent.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_agent.sv
@@ -5,15 +5,11 @@
 class pattgen_agent extends dv_base_agent #(
   .CFG_T           (pattgen_agent_cfg),
   .DRIVER_T        (pattgen_driver),
-  .HOST_DRIVER_T   (pattgen_host_driver),
-  .DEVICE_DRIVER_T (pattgen_device_driver),
   .SEQUENCER_T     (pattgen_sequencer),
   .MONITOR_T       (pattgen_monitor),
   .COV_T           (pattgen_agent_cov)
 );
-
   `uvm_component_utils(pattgen_agent)
-
   `uvm_component_new
 
   function void build_phase(uvm_phase phase);
@@ -22,15 +18,8 @@
     if (!uvm_config_db#(virtual pattgen_if)::get(this, "", "vif", cfg.vif)) begin
       `uvm_fatal(`gfn, "failed to get pattgen_if handle from uvm_config_db")
     end
-  endfunction
 
-  function void connect_phase(uvm_phase phase);
-    super.connect_phase(phase);
-    if (cfg.if_mode == dv_utils_pkg::Device) begin
-      `uvm_info(`gfn, "device_driver is used", UVM_DEBUG)
-    end else begin
-      `uvm_fatal(`gfn, "failed to connect driver to sequencer")
-    end
-  endfunction : connect_phase
+    `DV_CHECK_NE_FATAL(cfg.if_mode, dv_utils_pkg::Host, "Host mode not supported")
+  endfunction
 
 endclass
diff --git a/hw/dv/sv/pattgen_agent/pattgen_agent_cfg.sv b/hw/dv/sv/pattgen_agent/pattgen_agent_cfg.sv
index 2765a7e..bc29421 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_agent_cfg.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_agent_cfg.sv
@@ -3,17 +3,19 @@
 // SPDX-License-Identifier: Apache-2.0
 
 class pattgen_agent_cfg extends dv_base_agent_cfg;
-  bit en_monitor = 1'b1;
+  bit en_monitor = 1'b1; // enable monitor
 
   // interface handle used by driver, monitor & the sequencer, via cfg handle
   virtual pattgen_if vif;
 
-  bit polarity_ch0;
-  bit polarity_ch1;
+  bit reset_asserted;
+
+  bit [NUM_PATTGEN_CHANNELS-1:0] polarity;
+  int length[NUM_PATTGEN_CHANNELS-1:0];
 
   `uvm_object_utils_begin(pattgen_agent_cfg)
-    `uvm_field_int(polarity_ch0, UVM_DEFAULT)
-    `uvm_field_int(polarity_ch1, UVM_DEFAULT)
+    `uvm_field_sarray_int(polarity, UVM_DEFAULT)
+    `uvm_field_sarray_int(length,   UVM_DEFAULT)
   `uvm_object_utils_end
 
   `uvm_object_new
diff --git a/hw/dv/sv/pattgen_agent/pattgen_agent_cov.sv b/hw/dv/sv/pattgen_agent/pattgen_agent_cov.sv
index f0919a5..dbe366a 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_agent_cov.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_agent_cov.sv
@@ -5,11 +5,13 @@
 class pattgen_agent_cov extends dv_base_agent_cov #(pattgen_agent_cfg);
   `uvm_component_utils(pattgen_agent_cov)
 
+  // the base class provides the following handles for use:
+  // pattgen_agent_cfg: cfg
   // TODO: covergroups
 
   function new(string name, uvm_component parent);
     super.new(name, parent);
-    //TODO: instantiate all covergroups here
+    //TODO:  instantiate all covergroups here
   endfunction : new
 
-endclass : pattgen_agent_cov
+endclass
diff --git a/hw/dv/sv/pattgen_agent/pattgen_agent_pkg.sv b/hw/dv/sv/pattgen_agent/pattgen_agent_pkg.sv
index 377ca3e..6be7dd4 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_agent_pkg.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_agent_pkg.sv
@@ -12,6 +12,9 @@
   `include "uvm_macros.svh"
   `include "dv_macros.svh"
 
+  // TODO: consider to have a parameterized class
+  parameter uint NUM_PATTGEN_CHANNELS = 2;
+
   // local types
   // forward declare classes to allow typedefs below
   typedef class pattgen_item;
@@ -27,8 +30,6 @@
   `include "pattgen_agent_cov.sv"
   `include "pattgen_monitor.sv"
   `include "pattgen_driver.sv"
-  `include "pattgen_host_driver.sv"
-  `include "pattgen_device_driver.sv"
   `include "pattgen_agent.sv"
 
 endpackage: pattgen_agent_pkg
diff --git a/hw/dv/sv/pattgen_agent/pattgen_device_driver.sv b/hw/dv/sv/pattgen_agent/pattgen_device_driver.sv
deleted file mode 100644
index ed5fa99..0000000
--- a/hw/dv/sv/pattgen_agent/pattgen_device_driver.sv
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-class pattgen_device_driver extends pattgen_driver;
-  `uvm_component_utils(pattgen_device_driver)
-  `uvm_component_new
-
-  virtual task get_and_drive();
-    @(posedge cfg.vif.rst_ni);
-    // keep this as very simple task since pattgen DUT
-    // does not require responses from pattgen_agent
-  endtask : get_and_drive
-
-endclass : pattgen_device_driver
\ No newline at end of file
diff --git a/hw/dv/sv/pattgen_agent/pattgen_driver.sv b/hw/dv/sv/pattgen_agent/pattgen_driver.sv
index a73e010..a96a0c7 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_driver.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_driver.sv
@@ -9,10 +9,15 @@
   virtual task reset_signals();
     forever begin
       @(negedge cfg.vif.rst_ni);
-      `uvm_info(`gfn, "\n  driver in reset progress", UVM_DEBUG)
+      `uvm_info(`gfn, "\ndriver in reset progress", UVM_DEBUG)
       @(posedge cfg.vif.rst_ni);
-      `uvm_info(`gfn, "\n  driver out of reset", UVM_DEBUG)
+      `uvm_info(`gfn, "\ndriver out of reset", UVM_DEBUG)
     end
   endtask : reset_signals
 
+  virtual task get_and_drive();
+    @(posedge cfg.vif.rst_ni);
+    // pattgen does not require responses from pattgen_agent thus this task is kept to a minimum
+  endtask : get_and_drive
+
 endclass : pattgen_driver
diff --git a/hw/dv/sv/pattgen_agent/pattgen_host_driver.sv b/hw/dv/sv/pattgen_agent/pattgen_host_driver.sv
deleted file mode 100644
index 64be592..0000000
--- a/hw/dv/sv/pattgen_agent/pattgen_host_driver.sv
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-class pattgen_host_driver extends pattgen_driver;
-  `uvm_component_utils(pattgen_host_driver)
-  `uvm_component_new
-
-  // pattgen_agent is only operating in device mode
-endclass : pattgen_host_driver
diff --git a/hw/dv/sv/pattgen_agent/pattgen_if.sv b/hw/dv/sv/pattgen_agent/pattgen_if.sv
index c169fc1..eba4971 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_if.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_if.sv
@@ -2,37 +2,14 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
-import pattgen_agent_pkg::*;
-
-interface pattgen_if;
+interface pattgen_if #(
+  parameter int unsigned NumChannels = 2
+);
   logic clk_i;
   logic rst_ni;
 
   // standard pattgen interface pins
-  logic pda0_tx;
-  logic pcl0_tx;
-  logic pda1_tx;
-  logic pcl1_tx;
-
-  task automatic get_bit(string channel, bit polarity,
-                         output bit bit_o);
-    if (channel == "Channel0") begin
-      if (!polarity) begin
-        @(posedge pcl0_tx);
-      end else begin
-        @(negedge pcl0_tx);
-      end
-      bit_o = pda0_tx;
-    end else if (channel == "Channel1") begin
-      if (!polarity) begin
-        @(posedge pcl1_tx);
-      end else begin
-        @(negedge pcl1_tx);
-      end
-      bit_o = pda1_tx;
-    end else begin
-      bit_o = 1'bx;
-    end
-  endtask : get_bit
+  logic [NumChannels-1:0] pda_tx;
+  logic [NumChannels-1:0] pcl_tx;
 
 endinterface : pattgen_if
diff --git a/hw/dv/sv/pattgen_agent/pattgen_item.sv b/hw/dv/sv/pattgen_agent/pattgen_item.sv
index 3060a85..75165fe 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_item.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_item.sv
@@ -3,10 +3,12 @@
 // SPDX-License-Identifier: Apache-2.0
 
 class pattgen_item extends uvm_sequence_item;
-  bit data;
+  bit  data_q[$];
+  //uint length;
 
   `uvm_object_utils_begin(pattgen_item);
-    `uvm_field_int(data, UVM_DEFAULT)
+    //`uvm_field_int(length,       UVM_DEFAULT | UVM_NOCOMPARE)
+    `uvm_field_queue_int(data_q, UVM_DEFAULT)
   `uvm_object_utils_end
 
   `uvm_object_new
diff --git a/hw/dv/sv/pattgen_agent/pattgen_monitor.sv b/hw/dv/sv/pattgen_agent/pattgen_monitor.sv
index 9b97da0..9f4eeaa 100644
--- a/hw/dv/sv/pattgen_agent/pattgen_monitor.sv
+++ b/hw/dv/sv/pattgen_agent/pattgen_monitor.sv
@@ -11,68 +11,92 @@
   `uvm_component_new
 
   // analysis ports connected to scb
-  uvm_analysis_port #(pattgen_item) ch0_item_port;   // used to send items on ch0 to scb
-  uvm_analysis_port #(pattgen_item) ch1_item_port;   // used to send items on ch1 to scb
-
-  local pattgen_item ch0_dut_item;
-  local pattgen_item ch1_dut_item;
-
-  // counters for generated bits on channels
-  uint cnt_ch0 = 0;
-  uint cnt_ch1 = 0;
+  uvm_analysis_port #(pattgen_item) item_port[NUM_PATTGEN_CHANNELS];
 
   function void build_phase(uvm_phase phase);
     super.build_phase(phase);
-    ch0_item_port = new("ch0_item_port", this);
-    ch1_item_port = new("ch1_item_port", this);
-    ch0_dut_item  = new("ch0_dut_item");
-    ch1_dut_item  = new("ch1_dut_item");
+    for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
+      item_port[i] = new($sformatf("item_port[%0d]", i), this);
+    end
   endfunction : build_phase
 
   virtual task run_phase(uvm_phase phase);
     wait(cfg.vif.rst_ni);
     collect_trans(phase);
   endtask : run_phase
-  
-  // collect items forever
-  virtual protected task collect_trans(uvm_phase phase);
-    pattgen_item ch0_item, ch1_item;
 
-    forever begin
-      wait(cfg.en_monitor);
+  virtual protected task collect_trans(uvm_phase phase);
+    for (uint i = 0; i < NUM_PATTGEN_CHANNELS; i++) begin
       fork
-        begin // collect items on the channel 0
-          cfg.vif.get_bit(.channel("Channel0"), .polarity(cfg.polarity_ch0),
-                          .bit_o(ch0_dut_item.data));
-          `downcast(ch0_item, ch0_dut_item.clone());
-          ch0_item_port.write(ch0_item);
-        end
-        begin // collect items on the channel 1
-          cfg.vif.get_bit(.channel("Channel1"), .polarity(cfg.polarity_ch1),
-                          .bit_o(ch1_dut_item.data));
-          `downcast(ch1_item, ch1_dut_item.clone());
-          ch1_item_port.write(ch1_item);
-        end
-        begin // if (on-the-fly) reset is monitored, drop the item
-          @(negedge cfg.vif.rst_ni);
-          `uvm_info(`gfn, $sformatf("\nmonitor is reset, drop item on channel 0\n%s",
-              ch0_dut_item.sprint()), UVM_DEBUG)
-          `uvm_info(`gfn, $sformatf("\nmonitor is reset, drop item on channel 1\n%s",
-              ch1_dut_item.sprint()), UVM_DEBUG)
-        end
-      join_any
-      disable fork;
+        automatic uint channel = i;
+        collect_channel_trans(channel);
+        reset_thread();
+      join_none
     end
   endtask : collect_trans
 
+  virtual protected task collect_channel_trans(uint channel);
+    bit  bit_data;
+    uint bit_cnt;
+
+    pattgen_item dut_item;
+    forever begin
+      dut_item = pattgen_item::type_id::create("dut_item");
+      bit_cnt = 0;
+      fork 
+        begin : isolation_thread
+          fork
+            begin
+              do begin
+                get_pattgen_bit(channel, cfg.polarity[channel], bit_data);
+                dut_item.data_q.push_back(bit_data);
+                bit_cnt++;
+                `uvm_info(`gfn, $sformatf("\n--> monitor: channel %0d, polar %0b, data[%0d] %b",
+                    channel, cfg.polarity[channel], bit_cnt, bit_data), UVM_DEBUG)
+              end while (bit_cnt < cfg.length[channel]);
+              // avoid race condition (counter is achieved and reset is issued at the same time)
+              if (!cfg.reset_asserted) begin
+                item_port[channel].write(dut_item);
+                `uvm_info(`gfn, $sformatf("\n--> monitor: send dut_item on channel %0d to scb\n%s",
+                    channel, dut_item.sprint()), UVM_DEBUG)
+              end
+            end
+            @(posedge cfg.reset_asserted);
+          join_any
+          disable fork;
+        end : isolation_thread
+      join
+    end
+  endtask : collect_channel_trans
+
+  virtual task reset_thread();
+    forever begin
+      @(negedge cfg.vif.rst_ni);
+      cfg.reset_asserted = 1'b1;
+      // implement other clean-up actions under reset here
+      @(posedge cfg.vif.rst_ni);
+      cfg.reset_asserted = 1'b0;
+    end
+  endtask : reset_thread
+
   // update of_to_end to prevent sim finished when there is any activity on the bus
   // ok_to_end = 0 (bus busy) / 1 (bus idle)
   virtual task monitor_ready_to_end();
     forever begin
-      @(cfg.vif.pcl0_tx or cfg.vif.pda0_tx or cfg.vif.pcl1_tx or cfg.vif.pda1_tx);
-      ok_to_end = (cfg.vif.pcl0_tx == 1'b0) && (cfg.vif.pda0_tx == 1'b0) &&
-                  (cfg.vif.pcl1_tx == 1'b0) && (cfg.vif.pda1_tx == 1'b0);
+      @(cfg.vif.pcl_tx, cfg.vif.pda_tx);
+      ok_to_end = (cfg.vif.pcl_tx === {NUM_PATTGEN_CHANNELS{1'b0}}) &&
+                  (cfg.vif.pda_tx === {NUM_PATTGEN_CHANNELS{1'b0}});
     end
   endtask : monitor_ready_to_end
 
+  virtual task get_pattgen_bit(uint channel, bit polarity, output bit bit_o);
+    `DV_CHECK_LT_FATAL(channel, NUM_PATTGEN_CHANNELS, "invalid channel index")
+    if (polarity) begin
+      @(negedge cfg.vif.pcl_tx[channel]);
+    end else begin
+      @(posedge cfg.vif.pcl_tx[channel]);
+    end
+    bit_o = cfg.vif.pda_tx[channel];
+  endtask : get_pattgen_bit
+
 endclass : pattgen_monitor
diff --git a/hw/dv/sv/pattgen_agent/pattgen_sequencer.sv b/hw/dv/sv/pattgen_agent/pattgen_sequencer.sv
deleted file mode 100644
index e42a5a7..0000000
--- a/hw/dv/sv/pattgen_agent/pattgen_sequencer.sv
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-class pattgen_sequencer extends dv_base_sequencer#(pattgen_item, pattgen_agent_cfg);
-  `uvm_component_utils(pattgen_sequencer)
-  `uvm_component_new
-
-  // pattgen DUT does not require reponses from pattgen_agent thus no need extension
-endclass : pattgen_sequencer