[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;