[spi_device/dv] Update for passthrough

1. support testing invalid opcodes
2. support dummy cycles
3. a few fixes
4. rename op_code -> opcode

Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv b/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv
index d4d7afb..0147361 100644
--- a/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv
+++ b/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv
@@ -4,13 +4,14 @@
 
 class spi_host_flash_seq extends spi_base_seq;
 
-  rand bit [7:0] op_code;
+  rand bit [7:0] opcode;
+  // if address isn't provided, will be randomized based on cmd_infos
   rand bit [7:0] address_q[$];
   rand bit [7:0] payload_q[$];
   rand int          read_size;
 
   `uvm_object_utils_begin(spi_host_flash_seq)
-    `uvm_field_int(op_code,         UVM_DEFAULT)
+    `uvm_field_int(opcode,          UVM_DEFAULT)
     `uvm_field_int(read_size,       UVM_DEFAULT)
     `uvm_field_queue_int(payload_q, UVM_DEFAULT)
     `uvm_field_queue_int(address_q, UVM_DEFAULT)
@@ -18,17 +19,32 @@
   `uvm_object_new
 
   virtual task body();
+    int addr_bytes, num_lanes, dummy_cycles;
+    bit write_command;
+
     req = spi_item::type_id::create("req");
     start_item(req);
+
+    cfg.extract_cmd_info_from_opcode(opcode,
+        // output
+        addr_bytes, write_command, num_lanes, dummy_cycles);
+    if (address_q.size() == 0) begin
+      `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(address_q,
+          address_q.size == addr_bytes;)
+    end else begin
+      `DV_CHECK_EQ(address_q.size(), addr_bytes)
+    end
+
     `DV_CHECK_RANDOMIZE_WITH_FATAL(req,
                                    item_type == SpiFlashTrans;
-                                   opcode == local::op_code;
-                                   write_command == cfg.cmd_infos[op_code].write_command;
-                                   address_q.size() == cfg.cmd_infos[op_code].addr_bytes;
+                                   opcode == local::opcode;
+                                   write_command == local::write_command;
+                                   num_lanes == local::num_lanes;
+                                   dummy_cycles == local::dummy_cycles;
+                                   address_q.size() == addr_bytes;
                                    foreach (address_q[i]) {
                                      address_q[i] == local::address_q[i];
                                    }
-                                   num_lanes == cfg.cmd_infos[op_code].num_lanes;
                                    if (write_command) {
                                      read_size == 0;
                                      payload_q.size() == local::payload_q.size();
diff --git a/hw/dv/sv/spi_agent/spi_agent_cfg.sv b/hw/dv/sv/spi_agent/spi_agent_cfg.sv
index 3148a45..53bcb4f 100644
--- a/hw/dv/sv/spi_agent/spi_agent_cfg.sv
+++ b/hw/dv/sv/spi_agent/spi_agent_cfg.sv
@@ -136,9 +136,32 @@
   endfunction : get_sio_size
 
   virtual function void add_cmd_info(spi_flash_cmd_info info);
-    // op_code must be unique
-    `DV_CHECK_EQ(cmd_infos.exists(info.op_code), 0)
-    cmd_infos[info.op_code] = info;
+    // opcode must be unique
+    `DV_CHECK_EQ(is_opcode_supported(info.opcode), 0)
+    cmd_infos[info.opcode] = info;
   endfunction  : add_cmd_info
 
+  virtual function bit is_opcode_supported(bit [7:0] opcode);
+    return cmd_infos.exists(opcode);
+  endfunction  : is_opcode_supported
+
+  virtual function void extract_cmd_info_from_opcode(input bit [7:0] opcode,
+      output bit [2:0] addr_bytes,
+      output bit write_command,
+      output bit [2:0] num_lanes,
+      output int dummy_cycles);
+    if (cmd_infos.exists(opcode)) begin
+      addr_bytes    = cmd_infos[opcode].addr_bytes;
+      write_command = cmd_infos[opcode].write_command;
+      num_lanes     = cmd_infos[opcode].num_lanes;
+      dummy_cycles  = cmd_infos[opcode].dummy_cycles;
+    end else begin
+      // if it's invalid opcode, here is the default setting
+      `uvm_info(`gfn, $sformatf("extract invalid opcode: 0x%0h", opcode), UVM_MEDIUM)
+      write_command = 1;
+      addr_bytes    = 0;
+      num_lanes     = 1;
+      dummy_cycles  = 0;
+    end
+  endfunction  : extract_cmd_info_from_opcode
 endclass : spi_agent_cfg
diff --git a/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv b/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv
index 021b0b5..c36f8c5 100644
--- a/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv
+++ b/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv
@@ -5,11 +5,11 @@
 // this object stores the cfg info for a command, so that when a driver/monitor receives a flash
 // cmd, it knows how many addr_bytes, direction, dummy_cycles etc
 class spi_flash_cmd_info extends uvm_sequence_item;
-  rand bit [7:0] op_code;
+  rand bit [7:0] opcode;
   rand bit [2:0] addr_bytes;
   rand bit write_command;
-  rand bit [2:0] dummy_cycles; // TODO add support in driver and monitor
   rand bit [2:0] num_lanes;
+  rand int dummy_cycles; // TODO add support in driver and monitor
   rand bit addr_swap;
   rand bit data_swap;
 
@@ -29,14 +29,20 @@
     data_swap -> num_lanes == 1 &&  write_command == 1;
   }
 
+  constraint dummy_cycles_c {
+    dummy_cycles dist {
+      0       :/ 2,
+      [1:8]   :/ 2,
+      [9:100] :/ 1
+    };
+  }
   // TODO, simplify setting. Remove this later
   constraint simplify_c {
     addr_swap == 0;
     data_swap == 0;
-    dummy_cycles == 0;
   }
   `uvm_object_utils_begin(spi_flash_cmd_info)
-    `uvm_field_int(op_code,       UVM_DEFAULT)
+    `uvm_field_int(opcode,        UVM_DEFAULT)
     `uvm_field_int(addr_bytes,    UVM_DEFAULT)
     `uvm_field_int(write_command, UVM_DEFAULT)
     `uvm_field_int(dummy_cycles,  UVM_DEFAULT)
diff --git a/hw/dv/sv/spi_agent/spi_host_driver.sv b/hw/dv/sv/spi_agent/spi_host_driver.sv
index f80b637..bbba068 100644
--- a/hw/dv/sv/spi_agent/spi_host_driver.sv
+++ b/hw/dv/sv/spi_agent/spi_host_driver.sv
@@ -130,29 +130,40 @@
   endtask
 
   task drive_flash_item();
-    bit [7:0] drive_data[$];
+    bit [7:0] cmd_addr_bytes[$];
 
     `uvm_info(`gfn, $sformatf("Driving flash item: \n%s", req.sprint()), UVM_MEDIUM)
     cfg.vif.csb[cfg.csb_sel] <= 1'b0;
 
-    drive_data = {req.opcode, req.address_q, req.payload_q};
-    sck_pulses = drive_data.size() * 8;
-    if (!req.write_command) begin
+    cmd_addr_bytes = {req.opcode, req.address_q};
+    sck_pulses = cmd_addr_bytes.size() * 8 + req.dummy_cycles;
+    if (req.write_command) begin
+      `DV_CHECK_EQ(req.num_lanes, 1)
+      sck_pulses += req.payload_q.size * 8;
+    end else begin
       `DV_CHECK_EQ(req.payload_q.size, 0)
-      sck_pulses = sck_pulses + req.read_size * (8 / req.num_lanes);
+      sck_pulses += req.read_size * (8 / req.num_lanes);
     end
 
     // for mode 1 and 3, get the leading edges out of the way
     cfg.wait_sck_edge(LeadingEdge);
 
+    // driver cmd and address
+    issue_data(cmd_addr_bytes);
+
+    // align to DrivingEdge, if the item has more to send
+    if (req.dummy_cycles > 0 || req.payload_q.size > 0 ) cfg.wait_sck_edge(DrivingEdge);
+
+    repeat (req.dummy_cycles) begin
+      //cfg.vif.sio <= 'dz;
+      cfg.wait_sck_edge(DrivingEdge);
+    end
     // drive data
-    issue_data(drive_data);
+    issue_data(req.payload_q);
 
     wait(sck_pulses == 0);
-    if (cfg.csb_consecutive == 0) begin
-      cfg.vif.csb[cfg.csb_sel] <= 1'b1;
-      cfg.vif.sio[0] <= 1'bx;
-    end
+    cfg.vif.csb[cfg.csb_sel] <= 1'b1;
+    cfg.vif.sio <= 'dx;
   endtask
 
   task drive_sck_no_csb_item();
diff --git a/hw/dv/sv/spi_agent/spi_item.sv b/hw/dv/sv/spi_agent/spi_item.sv
index 7fa207d..6e120e9 100644
--- a/hw/dv/sv/spi_agent/spi_item.sv
+++ b/hw/dv/sv/spi_agent/spi_item.sv
@@ -17,7 +17,9 @@
   rand bit [7:0] address_q[$];
   rand bit [7:0] opcode;
   rand bit [2:0] num_lanes; // 1,2 or 4 lanes for read response
+  rand int dummy_cycles;
 
+  // for dummy transaction
   rand uint dummy_clk_cnt;
   rand uint dummy_sck_length_ns;
 
@@ -43,6 +45,7 @@
     `uvm_field_int(write_command,                UVM_DEFAULT)
     `uvm_field_int(opcode,                       UVM_DEFAULT)
     `uvm_field_int(num_lanes,                    UVM_DEFAULT)
+    `uvm_field_int(dummy_cycles,                 UVM_DEFAULT)
     `uvm_field_queue_int(payload_q,              UVM_DEFAULT)
     `uvm_field_queue_int(address_q,              UVM_DEFAULT)
   `uvm_object_utils_end
diff --git a/hw/dv/sv/spi_agent/spi_monitor.sv b/hw/dv/sv/spi_agent/spi_monitor.sv
index e6a17f9..ba12062 100644
--- a/hw/dv/sv/spi_agent/spi_monitor.sv
+++ b/hw/dv/sv/spi_agent/spi_monitor.sv
@@ -189,24 +189,31 @@
     fork
       begin: isolation_thread
         spi_item item = spi_item::type_id::create("host_item", this);
-        bit [7:0] opcode;
         bit opcode_received;
         fork
           begin: csb_deassert_thread
             wait(cfg.vif.csb[cfg.csb_sel] == 1'b1);
           end
           begin: sample_thread
+            int addr_bytes;
             opcode_received = 0;
+            item.item_type = SpiFlashTrans;
             // for mode 1 and 3, get the leading edges out of the way
             cfg.wait_sck_edge(LeadingEdge);
 
             // first byte is opcode. opcode or address is always sent on single mode
-            sample_flash_one_byte_data(.num_lanes(1), .is_device_rsp(0), .data(opcode));
+            sample_flash_one_byte_data(.num_lanes(1), .is_device_rsp(0), .data(item.opcode));
             opcode_received = 1;
-            extract_flash_cmd_info_via_opcode(item, opcode);
-            `uvm_info(`gfn, $sformatf("sampled flash opcode: 0x%0h", opcode), UVM_MEDIUM)
+            cfg.extract_cmd_info_from_opcode(item.opcode,
+                // output
+                addr_bytes, item.write_command, item.num_lanes, item.dummy_cycles);
+            `uvm_info(`gfn, $sformatf("sampled flash opcode: 0x%0h", item.opcode), UVM_MEDIUM)
 
-            sample_flash_address(cfg.cmd_infos[opcode].addr_bytes, item.address_q);
+            sample_flash_address(addr_bytes, item.address_q);
+
+            repeat (item.dummy_cycles) begin
+              cfg.wait_sck_edge(SamplingEdge);
+            end
             req_analysis_port.write(item);
 
             forever begin
@@ -227,36 +234,28 @@
     join
   endtask : collect_flash_trans
 
-  virtual function void extract_flash_cmd_info_via_opcode(spi_item item, bit[7:0] opcode);
-    `DV_CHECK_FATAL(cfg.cmd_infos.exists(opcode))
-    item.item_type = SpiFlashTrans;
-    item.opcode = opcode;
-    item.num_lanes = cfg.cmd_infos[opcode].num_lanes;
-    item.write_command = cfg.cmd_infos[opcode].write_command;
-  endfunction : extract_flash_cmd_info_via_opcode
-
   virtual task sample_flash_one_byte_data(input int num_lanes, input bit is_device_rsp,
-                                          output byte data);
+                                          output bit[7:0] data);
+    int which_bit = 8;
     for (int i = 0; i < 8; i += num_lanes) begin
-      int which_bit = cfg.host_bit_dir ? i : 7 - i;
       cfg.wait_sck_edge(SamplingEdge);
-      data[which_bit] = cfg.vif.sio[0];
       case(num_lanes)
-        1: data[which_bit] = is_device_rsp ? cfg.vif.sio[1] : cfg.vif.sio[0];
+        1: data[--which_bit] = is_device_rsp ? cfg.vif.sio[1] : cfg.vif.sio[0];
         2: begin
-          data[which_bit]     = cfg.vif.sio[0];
-          data[which_bit + 1] = cfg.vif.sio[1];
+          data[--which_bit] = cfg.vif.sio[1];
+          data[--which_bit] = cfg.vif.sio[0];
         end
         4: begin
-          data[which_bit]     = cfg.vif.sio[0];
-          data[which_bit + 1] = cfg.vif.sio[1];
-          data[which_bit + 2] = cfg.vif.sio[2];
-          data[which_bit + 3] = cfg.vif.sio[3];
+          data[--which_bit] = cfg.vif.sio[3];
+          data[--which_bit] = cfg.vif.sio[2];
+          data[--which_bit] = cfg.vif.sio[1];
+          data[--which_bit] = cfg.vif.sio[0];
         end
         default: `uvm_fatal(`gfn, $sformatf("Unsupported lanes num 0x%0h", num_lanes))
       endcase
     end
-    `uvm_info(`gfn, $sformatf("sampled one byte data for flash: 0x%0h", data), UVM_HIGH)
+    `DV_CHECK_EQ(which_bit, 0)
+    `uvm_info(`gfn, $sformatf("sampled one byte data for flash: 0x%0h", data), UVM_MEDIUM)
   endtask : sample_flash_one_byte_data
 
   // address is 3 or 4 bytes
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 78230c5..215ac10 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
@@ -223,13 +223,12 @@
   endtask
 
   // transfer in command including opcode, address and payload
-  virtual task spi_host_xfer_flash_item(bit [7:0] op, bit [7:0] addr_size,
-                                        uint payload_size);
+  virtual task spi_host_xfer_flash_item(bit [7:0] op, uint payload_size);
     spi_host_flash_seq m_spi_host_seq;
     `uvm_create_on(m_spi_host_seq, p_sequencer.spi_sequencer_h)
     `DV_CHECK_RANDOMIZE_WITH_FATAL(m_spi_host_seq,
-                                   op_code == op;
-                                   address_q.size() == addr_size;
+                                   opcode == op;
+                                   address_q.size() == 0;
                                    payload_q.size() == payload_size;
                                    read_size == payload_size;)
     `uvm_send(m_spi_host_seq)
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv
index 6df9ac0..59e89d1 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv
@@ -4,6 +4,12 @@
 
 // Passthrough base sequence
 class spi_device_pass_base_vseq extends spi_device_base_vseq;
+  // only enable this in 1-2 tests
+  bit allow_set_cmd_info_invalid;
+  bit allow_use_invalid_opcode;
+
+  bit [7:0] valid_opcode_q[$];
+
   `uvm_object_utils(spi_device_pass_base_vseq)
   `uvm_object_new
 
@@ -13,86 +19,88 @@
     // Configure the first 11 commands which are fixed
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes == 0 &&
-      info.op_code == READ_STATUS_1 &&
+      info.opcode == READ_STATUS_1 &&
       info.num_lanes == 1 &&
       info.write_command == 0;)
     add_cmd_info(info, 0);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes == 0 &&
-      info.op_code == READ_STATUS_2;
+      info.opcode == READ_STATUS_2;
       info.num_lanes == 1 &&
       info.write_command == 0;)
     add_cmd_info(info, 1);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes == 0 &&
-      info.op_code == READ_STATUS_3 &&
+      info.opcode == READ_STATUS_3 &&
       info.num_lanes == 1 &&
       info.write_command == 0;)
     add_cmd_info(info, 2);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes == 0 &&
-      info.op_code == READ_JEDEC &&
+      info.opcode == READ_JEDEC &&
       info.num_lanes == 1 &&
       info.write_command == 0;)
     add_cmd_info(info, 3);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes == 0 &&
-      info.op_code == READ_SFDP;
+      info.opcode == READ_SFDP;
       info.num_lanes == 1 &&
       info.write_command == 0;)
     add_cmd_info(info, 4);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes > 0 &&
-      info.op_code == READ_NORMAL &&
+      info.opcode == READ_NORMAL &&
       info.num_lanes == 1 &&
       info.write_command == 0;)
     add_cmd_info(info, 5);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes > 0 &&
-      info.op_code == READ_FAST &&
+      info.opcode == READ_FAST &&
       info.num_lanes == 1 &&
       info.write_command == 0;)
     add_cmd_info(info, 6);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes > 0 &&
-      info.op_code == READ_DUAL &&
+      info.opcode == READ_DUAL &&
       info.write_command == 0 &&
       info.num_lanes == 2;)
     add_cmd_info(info, 7);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes > 0 &&
-      info.op_code == READ_QUAD &&
+      info.opcode == READ_QUAD &&
       info.write_command == 0 &&
       info.num_lanes == 4;)
     add_cmd_info(info, 8);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes > 0 &&
-      info.op_code == READ_DUALIO &&
+      info.opcode == READ_DUALIO &&
       info.write_command == 0 &&
       info.num_lanes == 2;)
     add_cmd_info(info, 9);
     info = spi_flash_cmd_info::type_id::create("info");
     `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
       info.addr_bytes > 0 &&
-      info.op_code == READ_QUADIO &&
+      info.opcode == READ_QUADIO &&
       info.write_command == 0 &&
       info.num_lanes == 4;)
     add_cmd_info(info, 10);
     for (int i = 11; i < 24; i++) begin
       info = spi_flash_cmd_info::type_id::create("info");
       `DV_CHECK_RANDOMIZE_WITH_FATAL(info,
-        foreach (cfg.spi_host_agent_cfg.cmd_infos[j]) {info.op_code != j;})
+        foreach (cfg.spi_host_agent_cfg.cmd_infos[j]) {info.opcode != j;})
       add_cmd_info(info, i);
     end
+
+    valid_opcode_q = cfg.spi_host_agent_cfg.cmd_infos.find_index() with ('1);
   endtask : config_all_cmd_infos
 
   // Task for flash or pass init
@@ -136,6 +144,7 @@
 
     spi_device_flash_auto_rsp_nonblocking();
     randomize_mem();
+    randomize_all_cmd_filters();
   endtask : spi_device_flash_pass_init
 
   // Task for configuring enable/disable of command opcode
@@ -149,6 +158,13 @@
     csr_update(.csr(ral.cmd_filter[cmd_index]));
   endtask : cfg_cmd_filter
 
+  virtual task randomize_all_cmd_filters();
+    foreach (ral.cmd_filter[idx]) begin
+      `DV_CHECK_RANDOMIZE_FATAL(ral.cmd_filter[idx])
+      csr_update(.csr(ral.cmd_filter[idx]));
+    end
+  endtask : randomize_all_cmd_filters
+
   // Task for keeping opcode integrity regardless of rx_order config
   virtual task order_cmd_bits(bit [7:0] pass_cmd, bit[23:0] pass_addr, ref bit [31:0] addr_cmd);
     bit rx_order;
@@ -176,8 +192,15 @@
   virtual task add_cmd_info(spi_flash_cmd_info info, bit [4:0] idx);
     bit [3:0] lanes_en;
     addr_mode_e addr_size;
-    cfg.spi_host_agent_cfg.add_cmd_info(info);
-    cfg.spi_device_agent_cfg.add_cmd_info(info);
+    bit valid;
+
+    if (allow_set_cmd_info_invalid) valid = $urandom_range(0, 1);
+    else valid = 1;
+
+    if (valid) begin
+      cfg.spi_host_agent_cfg.add_cmd_info(info);
+      cfg.spi_device_agent_cfg.add_cmd_info(info);
+    end
 
     `uvm_info(`gfn, $sformatf("Add this cmd_info \n%s", info.sprint()), UVM_MEDIUM)
     case (info.num_lanes)
@@ -192,7 +215,6 @@
       4: addr_size = Addr4B;
       default : `uvm_fatal(`gfn, $sformatf("Unsupported addr bytes 0x%0h", info.addr_bytes))
     endcase
-    ral.cmd_info[idx].addr_mode.set(addr_size);
     // if addr_size is aligned with addr_4b_en, we could use AddrCfg instead of Addr4B/Addr3B
     if (`gmv(ral.cfg.addr_4b_en) == 1 && addr_size == Addr4B ||
          `gmv(ral.cfg.addr_4b_en) == 0 && addr_size == Addr3B) begin
@@ -200,8 +222,8 @@
     end
     ral.cmd_info[idx].addr_mode.set(addr_size);
 
-    ral.cmd_info[idx].valid.set(1'b1); // Enable this OPCODE
-    ral.cmd_info[idx].opcode.set(info.op_code);// Read Dual
+    ral.cmd_info[idx].valid.set(valid); // Enable this OPCODE
+    ral.cmd_info[idx].opcode.set(info.opcode);// Read Dual
     ral.cmd_info[idx].payload_en.set(lanes_en);
     ral.cmd_info[idx].payload_dir.set(!info.write_command);
     ral.cmd_info[idx].addr_swap_en.set(info.addr_swap);
@@ -209,4 +231,34 @@
     csr_update(.csr(ral.cmd_info[idx]));
   endtask : add_cmd_info
 
+  function bit [7:0] get_rand_opcode();
+    bit valid_op;
+    bit [7:0] op;
+
+    if (allow_use_invalid_opcode) begin
+        `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(valid_op,
+            valid_op dist {1 :/ 4, 0 :/ 1};)
+    end else begin
+      valid_op = 1;
+    end
+    `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(op,
+        if (valid_op) {
+          op inside {valid_opcode_q};
+        } else {
+          !(op inside {valid_opcode_q});
+        })
+    return op;
+  endfunction
+
+  function int get_rand_payload_size();
+    uint size;
+    `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(size,
+        size dist {
+           [0:5]    :/ 2,
+           128      :/ 1,
+           256      :/ 2, // typical value for a flash page size
+           512      :/ 1,
+           [6:1000] :/ 1};)
+    return size;
+  endfunction
 endclass : spi_device_pass_base_vseq
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv
index d9317d3..0107576 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_cmd_filtering_vseq.sv
@@ -9,28 +9,27 @@
 
   virtual task body();
     bit [7:0]  op;
-    bit [7:0] opcode_q[$];
     uint payload_size;
+
+    allow_set_cmd_info_invalid = 1;
+    allow_use_invalid_opcode = 1;
     spi_device_flash_pass_init(PassthroughMode);
 
-    // cmd_infos index is the opcode, get all opcode
-    opcode_q = cfg.spi_host_agent_cfg.cmd_infos.find_index() with ('1);
     for (int i = 0; i < num_trans; ++i) begin
-      `uvm_info(`gfn, $sformatf("running iteration %0d", i), UVM_LOW)
-      `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(op,
-          op inside {opcode_q};)
-      `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(payload_size,
-          // TODO, use distribution later
-          payload_size <= 256;)
+      op = get_rand_opcode;
+      `uvm_info(`gfn, $sformatf("running iteration %0d, test op = 0x%0h", i, op), UVM_LOW)
+      payload_size = 1; //get_rand_payload_size();
 
       // test 2 cases:
       //  - disable cmd filter, test cmd passthrough to downstream
       // - enable cmd filter, test cmd is blocked
       for (int cmd_filter = 0; cmd_filter < 2;  cmd_filter++) begin
         // Make sure filter is not blocking command opcode
+        `uvm_info(`gfn, $sformatf("sending op 0x%0h with filter = %0d", op, cmd_filter), UVM_MEDIUM)
         cfg_cmd_filter(cmd_filter, op);
         // Prepare data for transfer
-        spi_host_xfer_flash_item(op, cfg.spi_host_agent_cfg.cmd_infos[op].addr_bytes, payload_size);
+        spi_host_xfer_flash_item(op, payload_size);
+        cfg.clk_rst_vif.wait_clks(10);
       end
     end
 
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv
index 2a48ecc..e3da9d6 100644
--- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv
+++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_tpm_base_vseq.sv
@@ -23,8 +23,8 @@
   virtual task tpm_init();
     cfg.spi_host_agent_cfg.sck_polarity[0] = 0;
     cfg.spi_host_agent_cfg.sck_phase[0] = 0;
-    cfg.spi_host_agent_cfg.host_bit_dir = 1;
-    cfg.spi_host_agent_cfg.device_bit_dir = 1;
+    cfg.spi_host_agent_cfg.host_bit_dir = 0;
+    cfg.spi_host_agent_cfg.device_bit_dir = 0;
     ral.cfg.tx_order.set(1);
     ral.cfg.rx_order.set(1);
     ral.cfg.cpol.set(1'b0);
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 3b79297..049a4c5 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
@@ -153,12 +153,12 @@
   endfunction
 
   // return the index the cmd_filter for the input opcode
-  function automatic int get_cmd_filter_index(bit[7:0]  opcode);
+  function automatic int get_cmd_filter_index(bit[7:0] opcode);
     return opcode / 32;
   endfunction
 
   // return the field offset of the cmd_filter for the input opcode
-  function automatic int get_cmd_filter_offset(bit[7:0]  opcode);
+  function automatic int get_cmd_filter_offset(bit[7:0] opcode);
     return opcode % 32;
   endfunction
 
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 911e591..087b167 100644
--- a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
+++ b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
@@ -77,7 +77,11 @@
   function bit is_opcode_passthrough(bit[7:0] opcode);
     int cmd_index = get_cmd_filter_index(opcode);
     int cmd_offset = get_cmd_filter_offset(opcode);
-    return !(`gmv(ral.cmd_filter[cmd_index].filter[cmd_offset]));
+    bit filter = `gmv(ral.cmd_filter[cmd_index].filter[cmd_offset]);
+    bit valid_cmd = cfg.spi_host_agent_cfg.is_opcode_supported(opcode);
+
+    `uvm_info(`gfn, $sformatf("opcode filter: %0d, valid: %0d", filter, valid_cmd), UVM_MEDIUM)
+    return !filter && valid_cmd;
   endfunction
 
   // extract spi items sent from device
@@ -104,7 +108,10 @@
       `DV_CHECK_EQ(spi_passthrough_upstream_q.size, 1)
 
       upstream_item = spi_passthrough_upstream_q.pop_front();
-      `DV_CHECK_EQ(downstream_item.compare(upstream_item), 1)
+      if (!downstream_item.compare(upstream_item)) begin
+        `uvm_error(`gfn, $sformatf("Compare item failed\ndownstream item:\n%s, upstream item:\n%s",
+              downstream_item.sprint(), upstream_item.sprint()))
+      end
     end
   endtask