[dv/lc_ctrl] enhance smoke test

These PR did a few enhancement for the lc_ctrl smoke test:
1. Move the constraints to next_valid_lc_state request to
`lc_ctrl_env_pkg.sv` so we can reuse that in scb. Thanks weicai for the
help and suggestions. We found for an associative array, index cannot be
randomized with constraint, so we spilt it into a separate randomize
function within the sequence.

2. Minor clean up and add some comments.

3. Use all three registers for lc input token instead of one.

Signed-off-by: Cindy Chen <chencindy@google.com>
diff --git a/hw/ip/lc_ctrl/dv/env/lc_ctrl_env_pkg.sv b/hw/ip/lc_ctrl/dv/env/lc_ctrl_env_pkg.sv
index a4347a0..f49aac7 100644
--- a/hw/ip/lc_ctrl/dv/env/lc_ctrl_env_pkg.sv
+++ b/hw/ip/lc_ctrl/dv/env/lc_ctrl_env_pkg.sv
@@ -20,11 +20,32 @@
   `include "dv_macros.svh"
 
   // parameters
-  // TODO: add the names of alerts in order
   parameter string LIST_OF_ALERTS[] = {"lc_programming_failure", "lc_state_failure"};
   parameter uint   NUM_ALERTS = 2;
   parameter uint   CLAIM_TRANS_VAL = 'ha5;
 
+  // associative array cannot declare parameter here, so we used const instead
+  const dec_lc_state_e VALID_NEXT_STATES [dec_lc_state_e][$] = '{
+    DecLcStRma:     {DecLcStScrap},
+    DecLcStProdEnd: {DecLcStScrap},
+    DecLcStProd:    {DecLcStScrap, DecLcStRma},
+    DecLcStDev:     {DecLcStScrap, DecLcStRma},
+    DecLcStTestUnlocked3: {DecLcStScrap, DecLcStRma, DecLcStProdEnd, DecLcStProd, DecLcStDev},
+    DecLcStTestUnlocked2: {DecLcStScrap, DecLcStProdEnd, DecLcStProd, DecLcStDev,
+                           DecLcStTestLocked2},
+    DecLcStTestUnlocked1: {DecLcStScrap, DecLcStRma, DecLcStProdEnd, DecLcStProd, DecLcStDev,
+                           DecLcStTestLocked2, DecLcStTestLocked1},
+    DecLcStTestUnlocked0: {DecLcStScrap, DecLcStRma, DecLcStProdEnd, DecLcStProd, DecLcStDev,
+                           DecLcStTestLocked2, DecLcStTestLocked1, DecLcStTestLocked0},
+    DecLcStTestLocked2: {DecLcStScrap, DecLcStProdEnd, DecLcStProd,
+                         DecLcStDev, DecLcStTestUnlocked3},
+    DecLcStTestLocked1: {DecLcStScrap, DecLcStProdEnd, DecLcStProd, DecLcStDev,
+                         DecLcStTestUnlocked3, DecLcStTestUnlocked2},
+    DecLcStTestLocked0: {DecLcStScrap, DecLcStProdEnd, DecLcStProd, DecLcStDev,
+                         DecLcStTestUnlocked3, DecLcStTestUnlocked2, DecLcStTestUnlocked1},
+    DecLcStRaw: {DecLcStScrap, DecLcStTestUnlocked2, DecLcStTestUnlocked1, DecLcStTestUnlocked0}
+  };
+
   // types
   typedef enum bit [1:0] {
     LcPwrInitReq,
@@ -37,6 +58,33 @@
   typedef virtual lc_ctrl_if              lc_ctrl_vif;
 
   // functions
+  function automatic bit valid_state_for_trans(lc_state_e curr_state);
+    valid_state_for_trans = 0;
+    if (curr_state inside {LcStRma, LcStProdEnd, LcStProd, LcStDev, LcStTestUnlocked3,
+                          LcStTestUnlocked2, LcStTestUnlocked1, LcStTestUnlocked0,
+                          LcStTestLocked2, LcStTestLocked1, LcStTestLocked0, LcStRaw}) begin
+      valid_state_for_trans = 1;
+    end
+  endfunction
+
+  function automatic dec_lc_state_e dec_lc_state(lc_state_e curr_state);
+    case (curr_state)
+      LcStRaw:           return DecLcStRaw;
+      LcStTestUnlocked0: return DecLcStTestUnlocked0;
+      LcStTestLocked0:   return DecLcStTestLocked0;
+      LcStTestUnlocked1: return DecLcStTestUnlocked1;
+      LcStTestLocked1:   return DecLcStTestLocked1;
+      LcStTestUnlocked2: return DecLcStTestUnlocked2;
+      LcStTestLocked2:   return DecLcStTestLocked2;
+      LcStTestUnlocked3: return DecLcStTestUnlocked3;
+      LcStDev:           return DecLcStDev;
+      LcStProd:          return DecLcStProd;
+      LcStProdEnd:       return DecLcStProdEnd;
+      LcStRma:           return DecLcStRma;
+      LcStScrap:         return DecLcStScrap;
+      default: `uvm_fatal("lc_env_pkg", $sformatf("unknown lc_state 0x%0h", curr_state))
+    endcase
+  endfunction
 
   // package sources
   `include "lc_ctrl_env_cfg.sv"
diff --git a/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_base_vseq.sv b/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_base_vseq.sv
index 417c234..cd6e9f7 100644
--- a/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_base_vseq.sv
+++ b/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_base_vseq.sv
@@ -47,10 +47,12 @@
     cfg.pwr_lc_vif.drive_pin(LcPwrInitReq, 0);
   endtask
 
-  virtual task sw_transition_req(bit [TL_DW-1:0] next_lc_state, bit [TL_DW-1:0] token_val);
+  virtual task sw_transition_req(bit [TL_DW-1:0] next_lc_state, bit [TL_DW*3-1:0] token_val);
     csr_wr(ral.claim_transition_if, CLAIM_TRANS_VAL);
     csr_wr(ral.transition_target, next_lc_state);
-    csr_wr(ral.transition_token_0, token_val);
+    csr_wr(ral.transition_token_0, token_val[TL_DW-1:0]);
+    csr_wr(ral.transition_token_1, token_val[TL_DW*2-1:TL_DW]);
+    csr_wr(ral.transition_token_2, token_val[TL_DW*3-1:TL_DW*2]);
     csr_wr(ral.transition_cmd, 'h01);
     csr_spinwait(ral.status.transition_successful, 1);
   endtask
diff --git a/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_smoke_vseq.sv b/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_smoke_vseq.sv
index 9a2f940..ed97b34 100644
--- a/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_smoke_vseq.sv
+++ b/hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_smoke_vseq.sv
@@ -8,62 +8,35 @@
 
   `uvm_object_new
 
-  rand dec_lc_state_e next_lc_state;
+  dec_lc_state_e next_lc_state;
 
   constraint lc_cnt_c {
     lc_state != LcStRaw -> lc_cnt != LcCntRaw;
   }
 
-  constraint valid_next_lc_state_c {
-    // TODO: temp constraint, did not enable ram interface
-    next_lc_state != DecLcStRma;
-    lc_state == LcStRma     -> next_lc_state inside {DecLcStScrap};
-    lc_state == LcStProdEnd -> next_lc_state inside {DecLcStScrap};
-    lc_state == LcStProd    -> next_lc_state inside {DecLcStScrap, DecLcStRma};
-    lc_state == LcStDev     -> next_lc_state inside {DecLcStScrap, DecLcStRma};
-
-    lc_state == LcStTestUnlocked3 -> next_lc_state inside
-                {DecLcStScrap, DecLcStRma, DecLcStProdEnd, DecLcStProd, DecLcStDev};
-
-    lc_state == LcStTestLocked2   -> next_lc_state inside
-                {DecLcStScrap, DecLcStProdEnd, DecLcStProd, DecLcStDev, DecLcStTestUnlocked3};
-
-    lc_state == LcStTestUnlocked2 -> next_lc_state inside
-                {DecLcStScrap, DecLcStProdEnd, DecLcStProd, DecLcStDev, DecLcStTestLocked2};
-
-    lc_state == LcStTestLocked1   -> next_lc_state inside
-                {DecLcStScrap, DecLcStProdEnd, DecLcStProd, DecLcStDev, DecLcStTestUnlocked3,
-                 DecLcStTestUnlocked2};
-
-    lc_state == LcStTestUnlocked1 -> next_lc_state inside
-                {DecLcStScrap, DecLcStRma, DecLcStProdEnd, DecLcStProd, DecLcStDev,
-                 DecLcStTestLocked2, DecLcStTestLocked1};
-
-    lc_state == LcStTestLocked0   -> next_lc_state inside
-                {DecLcStScrap, DecLcStProdEnd, DecLcStProd, DecLcStDev, DecLcStTestUnlocked3,
-                 DecLcStTestUnlocked2, DecLcStTestUnlocked1};
-
-    lc_state == LcStTestUnlocked0 -> next_lc_state inside
-                {DecLcStScrap, DecLcStRma, DecLcStProdEnd, DecLcStProd, DecLcStDev,
-                 DecLcStTestLocked2, DecLcStTestLocked1, DecLcStTestLocked0};
-
-    lc_state == LcStRaw -> next_lc_state inside
-                {DecLcStScrap, DecLcStTestUnlocked2, DecLcStTestUnlocked1, DecLcStTestUnlocked0};
-  }
-
   task body();
     for (int i = 1; i <= num_trans; i++) begin
       if (i != 1) dut_init();
-
       `uvm_info(`gfn, $sformatf("starting seq %0d/%0d, init LC_state is %0s, LC_cnt is %0s",
                                 i, num_trans, lc_state.name, lc_cnt.name), UVM_MEDIUM)
 
       // SW transition request
-      if (lc_state != LcStScrap && lc_cnt != LcCnt16) begin
-        bit [TL_DW-1:0] token_val = $urandom();
+      if (valid_state_for_trans(lc_state) && lc_cnt != LcCnt16) begin
+        bit [TL_DW*3-1:0] token_val = {$urandom(), $urandom(), $urandom()};
+        randomize_next_lc_state(dec_lc_state(lc_state));
+        `uvm_info(`gfn, $sformatf("next_LC_state is %0s, input token is %0h", next_lc_state.name,
+                                  token_val), UVM_DEBUG)
         sw_transition_req(next_lc_state, token_val);
       end
     end
   endtask : body
 
+  // smoke test will always return valid next_lc_state
+  // need to randomize here because associative array's index cannot be a rand input in constraint
+  virtual function void randomize_next_lc_state(dec_lc_state_e curr_lc_state);
+    `DV_CHECK_STD_RANDOMIZE_WITH_FATAL(next_lc_state,
+        // TODO: temp constraint for no DecLcStRma
+        next_lc_state inside {VALID_NEXT_STATES[curr_lc_state]}; next_lc_state != DecLcStRma;)
+  endfunction
+
 endclass : lc_ctrl_smoke_vseq
diff --git a/hw/ip/lc_ctrl/dv/tb.sv b/hw/ip/lc_ctrl/dv/tb.sv
index a150bcf..80cc4b1 100644
--- a/hw/ip/lc_ctrl/dv/tb.sv
+++ b/hw/ip/lc_ctrl/dv/tb.sv
@@ -21,6 +21,7 @@
   // TODO: use push-pull agent
   wire lc_otp_token_rsp_t lc_rsp;
   assign lc_rsp.ack = 1;
+  // TODO: temp constraint to 0 because it has to equal to otp_lc_data_i tokens
   assign lc_rsp.hashed_token = 0;
 
   // interfaces