[otp_ctrl] Replace multibit access locks with mubi types

Signed-off-by: Michael Schaffner <msf@google.com>
diff --git a/hw/ip/otp_ctrl/otp_ctrl_pkg.core b/hw/ip/otp_ctrl/otp_ctrl_pkg.core
index fff0f12..08cfd90 100644
--- a/hw/ip/otp_ctrl/otp_ctrl_pkg.core
+++ b/hw/ip/otp_ctrl/otp_ctrl_pkg.core
@@ -9,6 +9,7 @@
     depend:
       - lowrisc:tlul:headers
       - lowrisc:ip:lc_ctrl_pkg
+      - lowrisc:prim:mubi
 
     files:
       - rtl/otp_ctrl_reg_pkg.sv
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index 5d3ef93..148daaa 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -83,6 +83,7 @@
   output logic [OtpTestVectWidth-1:0]                cio_test_en_o
 );
 
+  import prim_mubi_pkg::*;
   import prim_util_pkg::vbits;
 
   ////////////////////////
@@ -304,21 +305,23 @@
   // Access Defaults and CSRs //
   //////////////////////////////
 
-  part_access_t [NumPart-1:0] part_access_csrs;
+  part_access_t [NumPart-1:0] part_access;
   always_comb begin : p_access_control
     // Default (this will be overridden by partition-internal settings).
-    part_access_csrs = {{32'(2*NumPart)}{Unlocked}};
+    part_access = {{32'(2*NumPart)}{mubi8_lo_value()}};
     // Permanently lock DAI write and read access to the life cycle partition.
     // The LC partition can only be read from and written to via the LC controller.
-    part_access_csrs[LifeCycleIdx].write_lock = Locked;
-    part_access_csrs[LifeCycleIdx].read_lock = Locked;
+    part_access[LifeCycleIdx].write_lock = mubi8_hi_value();
+    part_access[LifeCycleIdx].read_lock = mubi8_hi_value();
 
     // Propagate CSR read enables down to the SW_CFG partitions.
-    if (!reg2hw.vendor_test_read_lock) part_access_csrs[VendorTestIdx].read_lock = Locked;
-    if (!reg2hw.creator_sw_cfg_read_lock) part_access_csrs[CreatorSwCfgIdx].read_lock = Locked;
-    if (!reg2hw.owner_sw_cfg_read_lock) part_access_csrs[OwnerSwCfgIdx].read_lock = Locked;
+    if (!reg2hw.vendor_test_read_lock) part_access[VendorTestIdx].read_lock = mubi8_hi_value();
+    if (!reg2hw.creator_sw_cfg_read_lock) part_access[CreatorSwCfgIdx].read_lock = mubi8_hi_value();
+    if (!reg2hw.owner_sw_cfg_read_lock) part_access[OwnerSwCfgIdx].read_lock = mubi8_hi_value();
     // The SECRET2 partition can only be accessed (write&read) when provisioning is enabled.
-    if (lc_creator_seed_sw_rw_en != lc_ctrl_pkg::On) part_access_csrs[Secret2Idx] = {2{Locked}};
+    if (lc_creator_seed_sw_rw_en != lc_ctrl_pkg::On) begin
+      part_access[Secret2Idx] = {2{mubi8_hi_value()}};
+    end
   end
 
   //////////////////////
@@ -1021,7 +1024,7 @@
         .init_done_o   ( part_init_done[k]            ),
         .escalate_en_i ( lc_escalate_en[k]            ),
         .error_o       ( part_error[k]                ),
-        .access_i      ( part_access_csrs[k]          ),
+        .access_i      ( part_access[k]               ),
         .access_o      ( part_access_dai[k]           ),
         .digest_o      ( part_digest[k]               ),
         .tlul_req_i    ( part_tlul_req[k]             ),
@@ -1078,7 +1081,7 @@
         // Only supported by life cycle partition (see further below).
         .check_byp_en_i    ( lc_ctrl_pkg::Off                ),
         .error_o           ( part_error[k]                   ),
-        .access_i          ( part_access_csrs[k]             ),
+        .access_i          ( part_access[k]                  ),
         .access_o          ( part_access_dai[k]              ),
         .digest_o          ( part_digest[k]                  ),
         .data_o            ( part_buf_data[PartInfo[k].offset +: PartInfo[k].size] ),
@@ -1129,7 +1132,7 @@
         // consistent with the values in the buffer regs anymore).
         .check_byp_en_i    ( lc_check_byp_en                 ),
         .error_o           ( part_error[k]                   ),
-        .access_i          ( part_access_csrs[k]             ),
+        .access_i          ( part_access[k]                  ),
         .access_o          ( part_access_dai[k]              ),
         .digest_o          ( part_digest[k]                  ),
         .data_o            ( part_buf_data[PartInfo[k].offset +: PartInfo[k].size] ),
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
index 9efa78f..51551cf 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
@@ -66,6 +66,7 @@
   // Integration Checks //
   ////////////////////////
 
+  import prim_mubi_pkg::*;
   import prim_util_pkg::vbits;
 
   localparam int CntWidth = OtpByteAddrWidth - $clog2(ScrmblBlockWidth/8);
@@ -281,7 +282,7 @@
       // that is the case, we immediately bail out. Otherwise, we
       // request a block of data from OTP.
       ReadSt: begin
-        if (part_access_i[part_idx].read_lock == Unlocked ||
+        if (mubi8_tst_lo_strict(part_access_i[part_idx].read_lock) ||
             // HW digests always remain readable.
             PartInfo[part_idx].hw_digest && otp_addr_o == digest_addr_lut[part_idx]) begin
           otp_req_o = 1'b1;
@@ -302,7 +303,7 @@
       // terminal error state.
       ReadWaitSt: begin
         // Continuously check read access and bail out if this is not consistent.
-        if (part_access_i[part_idx].read_lock == Unlocked ||
+        if (mubi8_tst_lo_strict(part_access_i[part_idx].read_lock) ||
             // HW digests always remain readable.
             PartInfo[part_idx].hw_digest && otp_addr_o == digest_addr_lut[part_idx]) begin
           if (otp_rvalid_i) begin
@@ -369,7 +370,7 @@
       // permanently write locked and can hence not be written via the DAI.
       WriteSt: begin
         dai_prog_idle_o = 1'b0;
-        if (part_access_i[part_idx].write_lock == Unlocked &&
+        if (mubi8_tst_lo_strict(part_access_i[part_idx].write_lock) &&
             // If this is a HW digest write to a buffered partition.
             ((PartInfo[part_idx].variant == Buffered && PartInfo[part_idx].hw_digest &&
               base_sel_q == PartOffset && otp_addr_o == digest_addr_lut[part_idx]) ||
@@ -398,7 +399,7 @@
       WriteWaitSt: begin
         dai_prog_idle_o = 1'b0;
         // Continuously check write access and bail out if this is not consistent.
-        if (part_access_i[part_idx].write_lock == Unlocked &&
+        if (mubi8_tst_lo_strict(part_access_i[part_idx].write_lock) &&
             // If this is a HW digest write to a buffered partition.
             ((PartInfo[part_idx].variant == Buffered && PartInfo[part_idx].hw_digest &&
               base_sel_q == PartOffset && otp_addr_o == digest_addr_lut[part_idx]) ||
@@ -440,7 +441,7 @@
       ScrSt: begin
         scrmbl_mtx_req_o = 1'b1;
         // Check write access and bail out if this is not consistent.
-        if (part_access_i[part_idx].write_lock == Unlocked &&
+        if (mubi8_tst_lo_strict(part_access_i[part_idx].write_lock) &&
             // If this is a non HW digest write to a buffered partition.
             (PartInfo[part_idx].variant == Buffered && PartInfo[part_idx].secret &&
              PartInfo[part_idx].hw_digest && base_sel_q == DaiOffset &&
@@ -464,7 +465,7 @@
       ScrWaitSt: begin
         scrmbl_mtx_req_o = 1'b1;
         // Continously check write access and bail out if this is not consistent.
-        if (part_access_i[part_idx].write_lock == Unlocked &&
+        if (mubi8_tst_lo_strict(part_access_i[part_idx].write_lock) &&
             // If this is a non HW digest write to a buffered partition.
             (PartInfo[part_idx].variant == Buffered && PartInfo[part_idx].secret &&
              PartInfo[part_idx].hw_digest && base_sel_q == DaiOffset &&
@@ -498,8 +499,8 @@
       // We also check here whether the partition has been write locked.
       DigReadSt: begin
         scrmbl_mtx_req_o = 1'b1;
-        if (part_access_i[part_idx].read_lock == Unlocked &&
-            part_access_i[part_idx].write_lock == Unlocked) begin
+        if (mubi8_tst_lo_strict(part_access_i[part_idx].read_lock) &&
+            mubi8_tst_lo_strict(part_access_i[part_idx].write_lock)) begin
           otp_req_o = 1'b1;
           otp_cmd_o = prim_otp_pkg::Read;
           if (otp_gnt_i) begin
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
index 4b1771f..6cf95b0 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
@@ -71,6 +71,7 @@
   // Integration Checks //
   ////////////////////////
 
+  import prim_mubi_pkg::*;
   import prim_util_pkg::vbits;
 
   localparam int unsigned DigestOffsetInt = (int'(Info.offset) +
@@ -156,7 +157,7 @@
   otp_err_e error_d, error_q;
   data_sel_e data_sel;
   base_sel_e base_sel;
-  access_e dout_gate_d, dout_gate_q;
+  mubi8_t dout_locked_d, dout_locked_q;
   logic [CntWidth-1:0] cnt_d, cnt_q;
   logic cnt_en, cnt_clr;
   logic ecc_err;
@@ -175,7 +176,7 @@
     state_d = state_q;
 
     // Redundantly encoded lock signal for buffer regs.
-    dout_gate_d = dout_gate_q;
+    dout_locked_d = dout_locked_q;
 
     // OTP signals
     otp_req_o = 1'b0;
@@ -409,8 +410,8 @@
         // This is the only way the buffer regs can get unlocked.
         end else begin
           state_d = IdleSt;
-          if (dout_gate_q == Locked) begin
-            dout_gate_d = Unlocked;
+          if (mubi8_tst_hi_strict(dout_locked_q)) begin
+            dout_locked_d = mubi8_lo_value();
           end
         end
       end
@@ -506,8 +507,8 @@
             state_d = IdleSt;
             // If the partition is still locked, this is the first integrity check after
             // initialization. This is the only way the buffer regs can get unlocked.
-            if (dout_gate_q == Locked) begin
-              dout_gate_d = Unlocked;
+            if (mubi8_tst_hi_strict(dout_locked_q)) begin
+              dout_locked_d = mubi8_lo_value();
             // Otherwise, this integrity check has requested by the LFSR timer, and we have
             // to acknowledge its completion.
             end else begin
@@ -527,7 +528,7 @@
       // Make sure the partition signals an error state if no error
       // code has been latched so far, and lock the buffer regs down.
       ErrorSt: begin
-        dout_gate_d = Locked;
+        dout_locked_d = mubi8_hi_value();
         if (error_q == NoError) begin
           error_d = FsmStateError;
         end
@@ -610,42 +611,40 @@
     .ecc_err_o ( ecc_err       )
   );
 
+  // We have successfully initialized the partition once it has been unlocked.
+  assign init_done_o = mubi8_tst_lo_strict(dout_locked_q);
   // Hardware output gating.
   // Note that this is decoupled from the DAI access rules further below.
-  assign data_o = (dout_gate_q == Unlocked) ? data : DataDefault;
+  assign data_o = (init_done_o) ? data : DataDefault;
   // The digest does not have to be gated.
   assign digest_o = data[$high(data_o) -: ScrmblBlockWidth];
-  // We have successfully initialized the partition once it has been unlocked.
-  assign init_done_o = (dout_gate_q == Unlocked);
-
 
   ////////////////////////
   // DAI Access Control //
   ////////////////////////
 
-  part_access_t access;
-  // Aggregate all possible DAI write locks. The partition is also locked when uninitialized.
+  // Aggregate all possible DAI write /readlocks. The partition is also locked when uninitialized.
   // Note that the locks are redundantly encoded values.
+  part_access_t access_pre, access;
+  assign access_pre.write_lock = mubi8_and_lo(dout_locked_q, access_i.write_lock);
+  assign access_pre.read_lock  = mubi8_and_lo(dout_locked_q, access_i.read_lock);
+
   if (Info.write_lock) begin : gen_digest_write_lock
-    assign access.write_lock = ((dout_gate_q != Unlocked) ||
-                                (access_i.write_lock != Unlocked) ||
-                                (digest_o != '0))  ? Locked : Unlocked;
-    `ASSERT(DigestWriteLocksPartition_A, digest_o |-> access.write_lock == Locked)
+    mubi8_t digest_locked;
+    assign digest_locked = (digest_o != '0) ? mubi8_hi_value() : mubi8_lo_value();
+    assign access.write_lock = mubi8_and_lo(access_pre.write_lock, digest_locked);
+    `ASSERT(DigestWriteLocksPartition_A, digest_o |-> mubi8_tst_hi_loose(access.write_lock))
   end else begin : gen_no_digest_write_lock
-    assign access.write_lock = ((dout_gate_q != Unlocked) ||
-                                (access_i.write_lock != Unlocked)) ? Locked : Unlocked;
+    assign access.write_lock = access_pre.write_lock;
   end
 
-  // Aggregate all possible DAI read locks. The partition is also locked when uninitialized.
-  // Note that the locks are redundantly encoded 16bit values.
   if (Info.read_lock) begin : gen_digest_read_lock
-    assign access.read_lock = ((dout_gate_q != Unlocked) ||
-                               (access_i.read_lock != Unlocked) ||
-                               (digest_o != '0)) ? Locked : Unlocked;
-    `ASSERT(DigestReadLocksPartition_A, digest_o |-> access.read_lock == Locked)
+    mubi8_t digest_locked;
+    assign digest_locked = (digest_o != '0) ? mubi8_hi_value() : mubi8_lo_value();
+    assign access.read_lock = mubi8_and_lo(access_pre.read_lock, digest_locked);
+    `ASSERT(DigestReadLocksPartition_A, digest_o |-> mubi8_tst_hi_loose(access.read_lock))
   end else begin : gen_no_digest_read_lock
-    assign access.read_lock = ((dout_gate_q != Unlocked) ||
-                               (access_i.read_lock != Unlocked)) ? Locked : Unlocked;
+    assign access.read_lock = access_pre.read_lock;
   end
 
   // Make sure there is a hand-picked buffer on each bit to prevent
@@ -680,13 +679,14 @@
 
   always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
     if (!rst_ni) begin
-      error_q     <= NoError;
-      cnt_q       <= '0;
-      dout_gate_q <= Locked;
+      error_q       <= NoError;
+      cnt_q         <= '0;
+      // data output is locked by default
+      dout_locked_q <= mubi8_hi_value();
     end else begin
-      error_q     <= error_d;
-      cnt_q       <= cnt_d;
-      dout_gate_q <= dout_gate_d;
+      error_q       <= error_d;
+      cnt_q         <= cnt_d;
+      dout_locked_q <= dout_locked_d;
     end
   end
 
@@ -716,22 +716,22 @@
 
   // Uninitialized partitions should always be locked, no matter what.
   `ASSERT(InitWriteLocksPartition_A,
-      dout_gate_q != Unlocked
+      mubi8_tst_hi_loose(dout_locked_q)
       |->
-      access_o.write_lock == Locked)
+      mubi8_tst_hi_loose(access_o.write_lock))
   `ASSERT(InitReadLocksPartition_A,
-      dout_gate_q != Unlocked
+      mubi8_tst_hi_loose(dout_locked_q)
       |->
-      access_o.read_lock == Locked)
+      mubi8_tst_hi_loose(access_o.read_lock))
   // Incoming Lock propagation
   `ASSERT(WriteLockPropagation_A,
-      access_i.write_lock != Unlocked
+      mubi8_tst_hi_loose(access_i.write_lock)
       |->
-      access_o.write_lock == Locked)
+      mubi8_tst_hi_loose(access_o.write_lock))
   `ASSERT(ReadLockPropagation_A,
-      access_i.read_lock != Unlocked
+      mubi8_tst_hi_loose(access_i.read_lock)
       |->
-      access_o.read_lock == Locked)
+      mubi8_tst_hi_loose(access_o.read_lock))
   // ECC error in buffer regs
   `ASSERT(EccErrorState_A,
       ecc_err
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
index 76259f1..0f541ed 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_unbuf.sv
@@ -55,6 +55,7 @@
   // Integration Checks //
   ////////////////////////
 
+  import prim_mubi_pkg::*;
   import prim_util_pkg::vbits;
 
   localparam logic [OtpByteAddrWidth:0] PartEnd = (OtpByteAddrWidth+1)'(Info.offset) +
@@ -214,7 +215,7 @@
         // Double check the address range.
         if ({tlul_addr_q, 2'b00} >= Info.offset &&
             {1'b0, tlul_addr_q, 2'b00} < PartEnd &&
-             access.read_lock == Unlocked) begin
+             mubi8_tst_lo_strict(access.read_lock)) begin
           otp_req_o = 1'b1;
           otp_addr_sel = DataAddr;
           if (otp_gnt_i) begin
@@ -340,30 +341,31 @@
   // DAI Access Control //
   ////////////////////////
 
+  mubi8_t init_locked;
+  assign init_locked = (~init_done_o) ? mubi8_hi_value() : mubi8_lo_value();
+
   // Aggregate all possible DAI write locks. The partition is also locked when uninitialized.
   // Note that the locks are redundantly encoded values.
+  part_access_t access_pre;
+  assign access_pre.write_lock = mubi8_and_lo(init_locked, access_i.write_lock);
+  assign access_pre.read_lock  = mubi8_and_lo(init_locked, access_i.read_lock);
+
   if (Info.write_lock) begin : gen_digest_write_lock
-    assign access.write_lock =
-        (~init_done_o || access_i.write_lock != Unlocked || digest_o != '0) ? Locked : Unlocked;
-
-    `ASSERT(DigestWriteLocksPartition_A, digest_o |-> access.write_lock == Locked)
-
+    mubi8_t digest_locked;
+    assign digest_locked = (digest_o != '0) ? mubi8_hi_value() : mubi8_lo_value();
+    assign access.write_lock = mubi8_and_lo(access_pre.write_lock, digest_locked);
+    `ASSERT(DigestWriteLocksPartition_A, digest_o |-> mubi8_tst_hi_loose(access.write_lock))
   end else begin : gen_no_digest_write_lock
-      assign access.write_lock =
-          (~init_done_o || access_i.write_lock != Unlocked) ? Locked : Unlocked;
+    assign access.write_lock = access_pre.write_lock;
   end
 
-  // Aggregate all possible DAI read locks. The partition is also locked when uninitialized.
-  // Note that the locks are redundantly encoded 16bit values.
   if (Info.read_lock) begin : gen_digest_read_lock
-    assign access.read_lock =
-        (~init_done_o || access_i.read_lock != Unlocked || digest_o != '0) ? Locked : Unlocked;
-
-    `ASSERT(DigestReadLocksPartition_A, digest_o |-> access.read_lock == Locked)
-
+    mubi8_t digest_locked;
+    assign digest_locked = (digest_o != '0) ? mubi8_hi_value() : mubi8_lo_value();
+    assign access.read_lock = mubi8_and_lo(access_pre.read_lock, digest_locked);
+    `ASSERT(DigestReadLocksPartition_A, digest_o |-> mubi8_tst_hi_loose(access.read_lock))
   end else begin : gen_no_digest_read_lock
-      assign access.read_lock =
-          (~init_done_o || access_i.read_lock != Unlocked) ? Locked : Unlocked;
+    assign access.read_lock = access_pre.read_lock;
   end
 
   // Make sure there is a hand-picked buffer on each bit to prevent
@@ -433,23 +435,23 @@
   `ASSERT(InitWriteLocksPartition_A,
       ~init_done_o
       |->
-      access_o.write_lock == Locked)
+      mubi8_tst_hi_loose(access_o.write_lock))
   `ASSERT(InitReadLocksPartition_A,
       ~init_done_o
       |->
-      access_o.read_lock == Locked)
+      mubi8_tst_hi_loose(access_o.read_lock))
   // Incoming Lock propagation
   `ASSERT(WriteLockPropagation_A,
-      access_i.write_lock != Unlocked
+      mubi8_tst_hi_loose(access_i.write_lock)
       |->
-      access_o.write_lock == Locked)
+      mubi8_tst_hi_loose(access_o.write_lock))
   `ASSERT(ReadLockPropagation_A,
-      access_i.read_lock != Unlocked
+      mubi8_tst_hi_loose(access_i.read_lock)
       |->
-      access_o.read_lock == Locked)
+      mubi8_tst_hi_loose(access_o.read_lock))
   // If the partition is read locked, the TL-UL access must error out
   `ASSERT(TlulReadOnReadLock_A,
-      tlul_req_i && tlul_gnt_o ##1 access_o.read_lock != Unlocked
+      tlul_req_i && tlul_gnt_o ##1 mubi8_tst_hi_loose(access_o.read_lock)
       |->
       tlul_rerror_o > '0 && tlul_rvalid_o)
   // ECC error in buffer regs.
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
index 905c90c..ea2bd83 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_pkg.sv
@@ -33,16 +33,10 @@
 
   // Redundantly encoded and complementary values are used to for signalling to the partition
   // controller FSMs and the DAI whether a partition is locked or not. Any other value than
-  // "Unlocked" is interpreted as "Locked" in those FSMs.
-  typedef enum logic [7:0] {
-    Unlocked = 8'h5A,
-    Locked   = 8'hA5
-  } access_e;
-
-  // Partition access type
+  // "Mubi8Lo" is interpreted as "Locked" in those FSMs.
   typedef struct packed {
-    access_e read_lock;
-    access_e write_lock;
+    prim_mubi_pkg::mubi8_t read_lock;
+    prim_mubi_pkg::mubi8_t write_lock;
   } part_access_t;
 
   parameter int DaiCmdWidth = 3;