[otp_ctrl] Switch to standardized prim_count
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/otp_ctrl/otp_ctrl.core b/hw/ip/otp_ctrl/otp_ctrl.core
index 159c101..7a604ca 100644
--- a/hw/ip/otp_ctrl/otp_ctrl.core
+++ b/hw/ip/otp_ctrl/otp_ctrl.core
@@ -14,6 +14,7 @@
- lowrisc:prim:ram_1p
- lowrisc:prim:otp
- lowrisc:prim:double_lfsr
+ - lowrisc:prim:count
- lowrisc:prim:lc_sync
- lowrisc:prim:buf
- lowrisc:prim:flop
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index 85a0a9e..627dbf7 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -1071,7 +1071,7 @@
cnsty_chk_req[k]};
// Alert assertion for sparse FSM.
- `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlPartBufFsmCheck_A,
+ `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlPartUnbufFsmCheck_A,
u_part_unbuf.u_state_regs, alert_tx_o[1])
////////////////////////////////////////////////////////////////////////////////////////////////
end else if (PartInfo[k].variant == Buffered) begin : gen_buffered
@@ -1127,6 +1127,8 @@
// Alert assertion for sparse FSM.
`ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlPartBufFsmCheck_A,
u_part_buf.u_state_regs, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntPartBufCheck_A,
+ u_part_buf.u_prim_count, alert_tx_o[1])
////////////////////////////////////////////////////////////////////////////////////////////////
end else if (PartInfo[k].variant == LifeCycle) begin : gen_lifecycle
otp_ctrl_part_buf #(
@@ -1193,6 +1195,8 @@
// Alert assertion for sparse FSM.
`ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlPartLcFsmCheck_A,
u_part_buf.u_state_regs, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntPartLcCheck_A,
+ u_part_buf.u_prim_count, alert_tx_o[1])
////////////////////////////////////////////////////////////////////////////////////////////////
end else begin : gen_invalid
// This is invalid and should break elaboration
@@ -1333,4 +1337,20 @@
`ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(CtrlScrambleFsmCheck_A,
u_otp_ctrl_scrmbl.u_state_regs, alert_tx_o[1])
+ // Alert assertions for redundant counters.
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntIntegCheck_A,
+ u_otp_ctrl_lfsr_timer.u_prim_count_integ, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntCnstyCheck_A,
+ u_otp_ctrl_lfsr_timer.u_prim_count_cnsty, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntDaiCheck_A,
+ u_otp_ctrl_dai.u_prim_count, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntKdiSeedCheck_A,
+ u_otp_ctrl_kdi.u_prim_count_seed, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntKdiEntropyCheck_A,
+ u_otp_ctrl_kdi.u_prim_count_entropy, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntLciCheck_A,
+ u_otp_ctrl_lci.u_prim_count, alert_tx_o[1])
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(CntScrmblCheck_A,
+ u_otp_ctrl_scrmbl.u_prim_count, alert_tx_o[1])
+
endmodule : otp_ctrl
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
index c2704fc..a0c420a 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_dai.sv
@@ -141,8 +141,8 @@
} addr_sel_e;
state_e state_d, state_q;
- logic [CntWidth-1:0] cnt_d, cnt_q;
- logic cnt_en, cnt_clr;
+ logic [CntWidth-1:0] cnt;
+ logic cnt_en, cnt_clr, cnt_err;
otp_err_e error_d, error_q;
logic data_en, data_clr;
data_sel_e data_sel;
@@ -550,7 +550,7 @@
// No need to digest the digest value itself
if (otp_addr_o == digest_addr_lut[part_idx]) begin
// Trigger digest round in case this is the second block in a row.
- if (!cnt_q[0]) begin
+ if (!cnt[0]) begin
scrmbl_cmd_o = Digest;
if (scrmbl_ready_i) begin
state_d = DigFinSt;
@@ -561,7 +561,7 @@
end
end else begin
// Trigger digest round in case this is the second block in a row.
- if (!cnt_q[0]) begin
+ if (!cnt[0]) begin
scrmbl_cmd_o = Digest;
end
// Go back and fetch more data blocks.
@@ -624,7 +624,7 @@
endcase // state_q
// Unconditionally jump into the terminal error state in case of escalation.
- if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ if (escalate_en_i != lc_ctrl_pkg::Off || cnt_err) begin
state_d = ErrorSt;
if (state_q != ErrorSt) begin
error_d = FsmStateError;
@@ -708,13 +708,26 @@
// Address counter - this is only used for computing a digest, hence the increment is
// fixed to 8 byte.
- assign cnt_d = (cnt_clr) ? '0 :
- (cnt_en) ? cnt_q + 1'b1 : cnt_q;
+ prim_count #(
+ .Width(CntWidth),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i(cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(cnt_en),
+ .step_i(CntWidth'(1)),
+ .cnt_o(cnt),
+ .err_o(cnt_err)
+ );
// Note that OTP works on halfword (16bit) addresses, hence need to
// shift the addresses appropriately.
logic [OtpByteAddrWidth-1:0] addr_calc;
- assign addr_calc = {cnt_q, {$clog2(ScrmblBlockWidth/8){1'b0}}} + addr_base;
+ assign addr_calc = {cnt, {$clog2(ScrmblBlockWidth/8){1'b0}}} + addr_base;
assign otp_addr_o = OtpAddrWidth'(addr_calc >> OtpAddrShift);
///////////////
@@ -739,12 +752,10 @@
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
error_q <= NoError;
- cnt_q <= '0;
data_q <= '0;
base_sel_q <= DaiOffset;
end else begin
error_q <= error_d;
- cnt_q <= cnt_d;
base_sel_q <= base_sel_d;
// Working register
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
index 8339c62..4e7b61d 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_kdi.sv
@@ -188,13 +188,41 @@
// Temporary Regs and Muxes //
//////////////////////////////
- logic seed_cnt_clr, seed_cnt_en, entropy_cnt_clr, entropy_cnt_en;
- logic [1:0] seed_cnt_d, seed_cnt_q, entropy_cnt_d, entropy_cnt_q;
+ localparam int CntWidth = 2;
+ logic seed_cnt_clr, seed_cnt_en, entropy_cnt_clr, entropy_cnt_en, seed_cnt_err, entropy_cnt_err;
+ logic [CntWidth-1:0] seed_cnt, entropy_cnt;
- assign seed_cnt_d = (seed_cnt_clr) ? '0 :
- (seed_cnt_en) ? seed_cnt_q + 1'b1 : seed_cnt_q;
- assign entropy_cnt_d = (entropy_cnt_clr) ? '0 :
- (entropy_cnt_en) ? entropy_cnt_q + 1'b1 : entropy_cnt_q;
+ prim_count #(
+ .Width(CntWidth),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count_seed (
+ .clk_i,
+ .rst_ni,
+ .clr_i(seed_cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(seed_cnt_en),
+ .step_i(CntWidth'(1)),
+ .cnt_o(seed_cnt),
+ .err_o(seed_cnt_err)
+ );
+
+ prim_count #(
+ .Width(CntWidth),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count_entropy (
+ .clk_i,
+ .rst_ni,
+ .clr_i(entropy_cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(entropy_cnt_en),
+ .step_i(CntWidth'(1)),
+ .cnt_o(entropy_cnt),
+ .err_o(entropy_cnt_err)
+ );
logic seed_valid_reg_en;
logic key_reg_en, nonce_reg_en;
@@ -207,10 +235,10 @@
nonce_out_d = nonce_out_q;
seed_valid_d = seed_valid_q;
if (key_reg_en) begin
- key_out_d[seed_cnt_q[1]] = scrmbl_data_i;
+ key_out_d[seed_cnt[1]] = scrmbl_data_i;
end
if (nonce_reg_en) begin
- nonce_out_d[entropy_cnt_q] = edn_data_i;
+ nonce_out_d[entropy_cnt] = edn_data_i;
end
if (seed_valid_reg_en) begin
seed_valid_d = req_bundle.seed_valid;
@@ -239,9 +267,9 @@
// Select correct 64bit block.
data_sel_e data_sel;
- assign scrmbl_data_o = (data_sel == EntropyData) ? nonce_out_q[entropy_cnt_q[0]] :
+ assign scrmbl_data_o = (data_sel == EntropyData) ? nonce_out_q[entropy_cnt[0]] :
// Gate seed value to '0 if invalid.
- (req_bundle.seed_valid) ? req_bundle.seed[seed_cnt_q] : '0;
+ (req_bundle.seed_valid) ? req_bundle.seed[seed_cnt] : '0;
/////////////////
// Control FSM //
@@ -360,7 +388,7 @@
scrmbl_mtx_req_o = 1'b1;
scrmbl_valid_o = 1'b1;
// Trigger digest round in case this is the second block in a row.
- if (seed_cnt_q[0]) begin
+ if (seed_cnt[0]) begin
scrmbl_cmd_o = Digest;
if (scrmbl_ready_i) begin
// Go and ingest a block of entropy if required.
@@ -384,7 +412,7 @@
if (edn_ack_i) begin
nonce_reg_en = 1'b1;
// Finished, go and acknowledge this request.
- if (entropy_cnt_q == 2'h1) begin
+ if (entropy_cnt == 2'h1) begin
state_d = DigEntropySt;
entropy_cnt_clr = 1'b1;
// Keep on requesting entropy.
@@ -401,7 +429,7 @@
scrmbl_valid_o = 1'b1;
// Trigger digest round in case this is the second block in a row,
// and go to digest finalization.
- if (entropy_cnt_q[0]) begin
+ if (entropy_cnt[0]) begin
scrmbl_cmd_o = Digest;
if (scrmbl_ready_i) begin
state_d = DigFinSt;
@@ -431,7 +459,7 @@
if (scrmbl_valid_i) begin
key_reg_en = 1'b1;
// Not finished yet, need to go back and produce second 64bit block.
- if (seed_cnt_q == 2'h1) begin
+ if (seed_cnt == 2'h1) begin
seed_cnt_en = 1'b1;
// In this case the previous digest state is kept,
// which leads to a chained digest.
@@ -464,7 +492,7 @@
if (edn_ack_i) begin
nonce_reg_en = 1'b1;
// Finished, go and acknowledge this request.
- if (entropy_cnt_q == req_bundle.nonce_size) begin
+ if (entropy_cnt == req_bundle.nonce_size) begin
state_d = FinishSt;
entropy_cnt_clr = 1'b1;
// Keep on requesting entropy.
@@ -494,7 +522,7 @@
endcase // state_q
// Unconditionally jump into the terminal error state in case of escalation.
- if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ if (escalate_en_i != lc_ctrl_pkg::Off || seed_cnt_err || entropy_cnt_err) begin
state_d = ErrorSt;
end
end
@@ -520,15 +548,11 @@
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
- seed_cnt_q <= '0;
- entropy_cnt_q <= '0;
key_out_q <= '0;
nonce_out_q <= '0;
seed_valid_q <= 1'b0;
edn_req_q <= 1'b0;
end else begin
- seed_cnt_q <= seed_cnt_d;
- entropy_cnt_q <= entropy_cnt_d;
key_out_q <= key_out_d;
nonce_out_q <= nonce_out_d;
seed_valid_q <= seed_valid_d;
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
index 1dc605d..f8116a0 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lci.sv
@@ -97,8 +97,8 @@
ErrorSt = 9'b011111101
} state_e;
- logic cnt_clr, cnt_en;
- logic [CntWidth-1:0] cnt_d, cnt_q;
+ logic cnt_clr, cnt_en, cnt_err;
+ logic [CntWidth-1:0] cnt;
otp_err_e error_d, error_q;
state_e state_d, state_q;
@@ -173,7 +173,7 @@
// Check whether we programmed all OTP words.
// If yes, we are done and can go back to idle.
- if (cnt_q == LastLcOtpWord) begin
+ if (cnt == LastLcOtpWord) begin
state_d = IdleSt;
lc_ack_o = 1'b1;
// If in any of the words a programming error has occurred,
@@ -208,7 +208,7 @@
endcase // state_q
// Unconditionally jump into the terminal error state in case of escalation.
- if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ if (escalate_en_i != lc_ctrl_pkg::Off || cnt_err) begin
state_d = ErrorSt;
if (error_q == NoError) begin
error_d = FsmStateError;
@@ -222,20 +222,33 @@
//////////////////////////////
// Native OTP word counter
- assign cnt_d = (cnt_clr) ? '0 :
- (cnt_en) ? cnt_q + 1'b1 : cnt_q;
+ prim_count #(
+ .Width(CntWidth),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i(cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(cnt_en),
+ .step_i(CntWidth'(1)),
+ .cnt_o(cnt),
+ .err_o(cnt_err)
+ );
// The output address is "offset + count", but we have to convert Info.offset from a byte address
// to a halfword (16-bit) address by discarding the bottom OtpAddrShift bits. We also make the
- // zero-extension of cnt_q explicit (to avoid width mismatch warnings).
- assign otp_addr_o = Info.offset[OtpByteAddrWidth-1:OtpAddrShift] + OtpAddrWidth'(cnt_q);
+ // zero-extension of cnt explicit (to avoid width mismatch warnings).
+ assign otp_addr_o = Info.offset[OtpByteAddrWidth-1:OtpAddrShift] + OtpAddrWidth'(cnt);
// Always transfer 16bit blocks.
assign otp_size_o = '0;
logic [NumLcOtpWords-1:0][OtpWidth-1:0] data;
assign data = lc_data_i;
- assign otp_wdata_o = (otp_req_o) ? OtpIfWidth'(data[cnt_q]) : '0;
+ assign otp_wdata_o = (otp_req_o) ? OtpIfWidth'(data[cnt]) : '0;
logic unused_rdata;
assign unused_rdata = ^otp_rdata_i;
@@ -262,10 +275,8 @@
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
error_q <= NoError;
- cnt_q <= '0;
end else begin
error_q <= error_d;
- cnt_q <= cnt_d;
end
end
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
index 7ec2d67..5d8abed 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_lfsr_timer.sv
@@ -118,78 +118,61 @@
// Tandem Counter Instances //
//////////////////////////////
- logic [1:0][LfsrWidth-1:0] integ_cnt_q;
- logic [1:0][LfsrWidth-1:0] cnsty_cnt_q;
- logic integ_load_period, integ_load_timeout, integ_cnt_zero;
- logic cnsty_load_period, cnsty_load_timeout, cnsty_cnt_zero;
-
- logic [LfsrWidth-1:0] integ_mask, cnsty_mask;
- assign integ_mask = {integ_period_msk_i, {LfsrWidth-32{1'b1}}};
- assign cnsty_mask = {cnsty_period_msk_i, {LfsrWidth-32{1'b1}}};
-
- logic timeout_zero, integ_msk_zero, cnsty_msk_zero, cnsty_cnt_pause;
- assign timeout_zero = (timeout_i == '0);
- assign integ_msk_zero = (integ_period_msk_i == '0);
- assign cnsty_msk_zero = (cnsty_period_msk_i == '0);
- assign integ_cnt_zero = (integ_cnt_q[0] == '0);
- assign cnsty_cnt_zero = (cnsty_cnt_q[0] == '0);
-
// We employ redundant counters to guard against FI attacks.
// If any of them is glitched and the redundant counter states do not agree,
// the FSM below is moved into a terminal error state.
- for (genvar k = 0; k < 2; k++) begin : gen_double_cnt
- // Instantiate size_only buffers to prevent
- // optimization / merging of redundant logic.
- logic integ_load_period_buf, integ_load_timeout_buf;
- logic cnsty_load_period_buf, cnsty_load_timeout_buf, cnsty_cnt_pause_buf;
+ logic [LfsrWidth-1:0] integ_cnt, cnsty_cnt, integ_cnt_set_val, cnsty_cnt_set_val;
+ logic [LfsrWidth-1:0] integ_mask, cnsty_mask;
+ logic integ_set_period, integ_set_timeout, integ_cnt_zero;
+ logic cnsty_set_period, cnsty_set_timeout, cnsty_cnt_zero;
+ logic integ_cnt_set, cnsty_cnt_set, integ_cnt_err, cnsty_cnt_err;
+ logic timeout_zero, integ_msk_zero, cnsty_msk_zero, cnsty_cnt_pause;
- prim_buf #(
- .Width(5)
- ) u_prim_buf (
- .in_i({integ_load_period,
- integ_load_timeout,
- cnsty_load_period,
- cnsty_load_timeout,
- cnsty_cnt_pause}),
- .out_o({integ_load_period_buf,
- integ_load_timeout_buf,
- cnsty_load_period_buf,
- cnsty_load_timeout_buf,
- cnsty_cnt_pause_buf})
- );
+ assign timeout_zero = (timeout_i == '0);
+ assign integ_msk_zero = (integ_period_msk_i == '0);
+ assign cnsty_msk_zero = (cnsty_period_msk_i == '0);
+ assign integ_cnt_zero = (integ_cnt == '0);
+ assign cnsty_cnt_zero = (cnsty_cnt == '0);
- logic [LfsrWidth-1:0] integ_cnt_d;
- logic [LfsrWidth-1:0] cnsty_cnt_d;
- assign integ_cnt_d = (integ_load_period_buf) ? lfsr_state & integ_mask :
- (integ_load_timeout_buf) ? LfsrWidth'(timeout_i) :
- (integ_cnt_q[k] == '0) ? '0 :
- integ_cnt_q[k] - 1'b1;
+ assign integ_cnt_set = integ_set_period || integ_set_timeout;
+ assign cnsty_cnt_set = cnsty_set_period || cnsty_set_timeout;
+ assign integ_mask = {integ_period_msk_i, {LfsrWidth-32{1'b1}}};
+ assign cnsty_mask = {cnsty_period_msk_i, {LfsrWidth-32{1'b1}}};
+ assign integ_cnt_set_val = (integ_set_period) ? (lfsr_state & integ_mask) : LfsrWidth'(timeout_i);
+ assign cnsty_cnt_set_val = (cnsty_set_period) ? (lfsr_state & cnsty_mask) : LfsrWidth'(timeout_i);
- assign cnsty_cnt_d = (cnsty_load_period_buf) ? lfsr_state & cnsty_mask :
- (cnsty_load_timeout_buf) ? LfsrWidth'(timeout_i) :
- (cnsty_cnt_q[k] == '0) ? '0 :
- (cnsty_cnt_pause_buf) ? cnsty_cnt_q[k] :
- cnsty_cnt_q[k] - 1'b1;
+ prim_count #(
+ .Width(LfsrWidth),
+ .OutSelDnCnt(1), // count down
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count_integ (
+ .clk_i,
+ .rst_ni,
+ .clr_i(1'b0),
+ .set_i(integ_cnt_set),
+ .set_cnt_i(integ_cnt_set_val),
+ .en_i(!integ_cnt_zero),
+ .step_i(LfsrWidth'(1)),
+ .cnt_o(integ_cnt),
+ .err_o(integ_cnt_err)
+ );
- prim_flop #(
- .Width(LfsrWidth)
- ) u_prim_flop_integ_cnt (
- .clk_i,
- .rst_ni,
- .d_i ( integ_cnt_d ),
- .q_o ( integ_cnt_q[k] )
- );
-
- prim_flop #(
- .Width(LfsrWidth)
- ) u_prim_flop_cnsty_cnt (
- .clk_i,
- .rst_ni,
- .d_i ( cnsty_cnt_d ),
- .q_o ( cnsty_cnt_q[k] )
- );
- end
+ prim_count #(
+ .Width(LfsrWidth),
+ .OutSelDnCnt(1), // count down
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count_cnsty (
+ .clk_i,
+ .rst_ni,
+ .clr_i(1'b0),
+ .set_i(cnsty_cnt_set),
+ .set_cnt_i(cnsty_cnt_set_val),
+ .en_i(!cnsty_cnt_zero && !cnsty_cnt_pause),
+ .step_i(LfsrWidth'(1)),
+ .cnt_o(cnsty_cnt),
+ .err_o(cnsty_cnt_err)
+ );
/////////////////////
// Request signals //
@@ -258,10 +241,10 @@
// LFSR and counter signals
lfsr_en = 1'b0;
- integ_load_period = 1'b0;
- cnsty_load_period = 1'b0;
- integ_load_timeout = 1'b0;
- cnsty_load_timeout = 1'b0;
+ integ_set_period = 1'b0;
+ cnsty_set_period = 1'b0;
+ integ_set_timeout = 1'b0;
+ cnsty_set_timeout = 1'b0;
cnsty_cnt_pause = 1'b0;
// Requests going to partitions.
@@ -293,12 +276,12 @@
IdleSt: begin
if ((!integ_msk_zero && integ_cnt_zero) || integ_chk_trig_q) begin
state_d = IntegWaitSt;
- integ_load_timeout = 1'b1;
+ integ_set_timeout = 1'b1;
set_all_integ_reqs = 1'b1;
clr_integ_chk_trig = integ_chk_trig_q;
end else if ((!cnsty_msk_zero && cnsty_cnt_zero) || cnsty_chk_trig_q) begin
state_d = CnstyWaitSt;
- cnsty_load_timeout = 1'b1;
+ cnsty_set_timeout = 1'b1;
set_all_cnsty_reqs = 1'b1;
clr_cnsty_chk_trig = cnsty_chk_trig_q;
end
@@ -315,7 +298,7 @@
end else if (integ_chk_req_q == '0) begin
state_d = IdleSt;
// This draws the next wait period.
- integ_load_period = 1'b1;
+ integ_set_period = 1'b1;
lfsr_en = 1'b1;
end
end
@@ -337,7 +320,7 @@
end else if (cnsty_chk_req_q == '0) begin
state_d = IdleSt;
// This draws the next wait period.
- cnsty_load_period = 1'b1;
+ cnsty_set_period = 1'b1;
lfsr_en = 1'b1;
end
end
@@ -362,10 +345,7 @@
// Unconditionally jump into the terminal error state in case of escalation,
// or if the two LFSR or counter states do not agree.
- if (lfsr_err ||
- integ_cnt_q[0] != integ_cnt_q[1] ||
- cnsty_cnt_q[0] != cnsty_cnt_q[1] ||
- escalate_en_i != lc_ctrl_pkg::Off) begin
+ if (lfsr_err || integ_cnt_err || cnsty_cnt_err || escalate_en_i != lc_ctrl_pkg::Off) begin
state_d = ErrorSt;
end
end
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 1367f2f..a30b43b 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_part_buf.sv
@@ -163,8 +163,8 @@
data_sel_e data_sel;
base_sel_e base_sel;
mubi8_t dout_locked_d, dout_locked_q;
- logic [CntWidth-1:0] cnt_d, cnt_q;
- logic cnt_en, cnt_clr;
+ logic [CntWidth-1:0] cnt;
+ logic cnt_en, cnt_clr, cnt_err;
logic ecc_err;
logic buffer_reg_en;
logic [ScrmblBlockWidth-1:0] data_mux;
@@ -245,7 +245,7 @@
// Once we've read and descrambled the whole partition, we can go to integrity
// verification. Note that the last block is the digest value, which does not
// have to be descrambled.
- if (cnt_q == LastScrmblBlock) begin
+ if (cnt == LastScrmblBlock) begin
state_d = IntegDigClrSt;
// Only need to descramble if this is a scrambled partition.
// Otherwise, we can just go back to InitSt and read the next block.
@@ -357,7 +357,7 @@
if (scrmbl_data_o == data_mux || check_byp_en_i == lc_ctrl_pkg::On) begin
// Can go back to idle and acknowledge the
// request if this is the last block.
- if (cnt_q == LastScrmblBlock) begin
+ if (cnt == LastScrmblBlock) begin
state_d = IdleSt;
cnsty_chk_ack_o = 1'b1;
// Need to go back and read out more blocks.
@@ -452,11 +452,11 @@
if (scrmbl_ready_i) begin
cnt_en = 1'b1;
// No need to digest the digest value itself
- if (cnt_q == PenultimateScrmblBlock) begin
+ if (cnt == PenultimateScrmblBlock) begin
// Note that the digest operates on 128bit blocks since the data is fed in via the
// PRESENT key input. Therefore, we only trigger a digest update on every second
// 64bit block that is pushed into the scrambling datapath.
- if (cnt_q[0]) begin
+ if (cnt[0]) begin
scrmbl_cmd_o = Digest;
state_d = IntegDigFinSt;
end else begin
@@ -465,7 +465,7 @@
end
end else begin
// Trigger digest round in case this is the second block in a row.
- if (cnt_q[0]) begin
+ if (cnt[0]) begin
scrmbl_cmd_o = Digest;
end
// Go back and scramble the next data block if this is
@@ -560,7 +560,7 @@
error_d = CheckFailError;
end
end
- if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ if (escalate_en_i != lc_ctrl_pkg::Off || cnt_err) begin
state_d = ErrorSt;
if (state_q != ErrorSt) begin
error_d = FsmStateError;
@@ -574,8 +574,21 @@
// Address counter - this is only used for computing a digest, hence the increment is
// fixed to 8 byte.
- assign cnt_d = (cnt_clr) ? '0 :
- (cnt_en) ? cnt_q + 1'b1 : cnt_q;
+ prim_count #(
+ .Width(CntWidth),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i(cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(cnt_en),
+ .step_i(CntWidth'(1)),
+ .cnt_o(cnt),
+ .err_o(cnt_err)
+ );
logic [OtpByteAddrWidth-1:0] addr_base;
assign addr_base = (base_sel == DigOffset) ? DigestOffset : Info.offset;
@@ -583,7 +596,7 @@
// Note that OTP works on halfword (16bit) addresses, hence need to
// shift the addresses appropriately.
logic [OtpByteAddrWidth-1:0] addr_calc;
- assign addr_calc = OtpByteAddrWidth'({cnt_q, {$clog2(ScrmblBlockWidth/8){1'b0}}}) + addr_base;
+ assign addr_calc = OtpByteAddrWidth'({cnt, {$clog2(ScrmblBlockWidth/8){1'b0}}}) + addr_base;
assign otp_addr_o = addr_calc[OtpByteAddrWidth-1:OtpAddrShift];
if (OtpAddrShift > 0) begin : gen_unused
@@ -595,7 +608,7 @@
assign otp_size_o = OtpSizeWidth'(unsigned'(ScrmblBlockWidth / OtpWidth) - 1);
logic [Info.size*8-1:0] data;
- assign scrmbl_data_o = data[{cnt_q, {$clog2(ScrmblBlockWidth){1'b0}}} +: ScrmblBlockWidth];
+ assign scrmbl_data_o = data[{cnt, {$clog2(ScrmblBlockWidth){1'b0}}} +: ScrmblBlockWidth];
assign data_mux = (data_sel == ScrmblData) ? scrmbl_data_i : otp_rdata_i;
@@ -610,7 +623,7 @@
.clk_i,
.rst_ni,
.wren_i ( buffer_reg_en ),
- .addr_i ( cnt_q ),
+ .addr_i ( cnt ),
.wdata_i ( data_mux ),
.data_o ( data ),
.ecc_err_o ( ecc_err )
@@ -686,12 +699,10 @@
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
error_q <= NoError;
- cnt_q <= '0;
// data output is locked by default
dout_locked_q <= MuBi8True;
end else begin
error_q <= error_d;
- cnt_q <= cnt_d;
dout_locked_q <= dout_locked_d;
end
end
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
index 0682ebc..6758f00 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl_scrmbl.sv
@@ -238,15 +238,27 @@
localparam bit [CntWidth-1:0] LastPresentRound = LastPresentRoundInt[CntWidth-1:0];
state_e state_d, state_q;
- logic [CntWidth-1:0] cnt_d, cnt_q;
- logic cnt_clr, cnt_en;
+ logic [CntWidth-1:0] cnt;
+ logic cnt_clr, cnt_en, cnt_err;
logic valid_d, valid_q;
assign valid_o = valid_q;
- assign cnt_d = (cnt_clr) ? '0 :
- (cnt_en) ? cnt_q + 1 :
- cnt_q;
+ prim_count #(
+ .Width(CntWidth),
+ .OutSelDnCnt(0), // count up
+ .CntStyle(prim_count_pkg::CrossCnt)
+ ) u_prim_count (
+ .clk_i,
+ .rst_ni,
+ .clr_i(cnt_clr),
+ .set_i(1'b0),
+ .set_cnt_i('0),
+ .en_i(cnt_en),
+ .step_i(CntWidth'(1)),
+ .cnt_o(cnt),
+ .err_o(cnt_err)
+ );
always_comb begin : p_fsm
state_d = state_q;
@@ -326,7 +338,7 @@
data_state_en = 1'b1;
key_state_en = 1'b1;
cnt_en = 1'b1;
- if (cnt_q == LastPresentRound) begin
+ if (cnt == LastPresentRound) begin
state_d = IdleSt;
valid_d = 1'b1;
end
@@ -339,7 +351,7 @@
data_state_en = 1'b1;
key_state_en = 1'b1;
cnt_en = 1'b1;
- if (cnt_q == LastPresentRound) begin
+ if (cnt == LastPresentRound) begin
state_d = IdleSt;
valid_d = 1'b1;
end
@@ -353,7 +365,7 @@
data_state_en = 1'b1;
key_state_en = 1'b1;
cnt_en = 1'b1;
- if (cnt_q == LastPresentRound) begin
+ if (cnt == LastPresentRound) begin
state_d = IdleSt;
valid_d = 1'b1;
// Apply XOR for Davies-Meyer construction.
@@ -379,7 +391,7 @@
endcase // state_q
// Unconditionally jump into the terminal error state in case of escalation.
- if (escalate_en_i != lc_ctrl_pkg::Off) begin
+ if (escalate_en_i != lc_ctrl_pkg::Off || cnt_err) begin
state_d = ErrorSt;
end
end
@@ -437,7 +449,6 @@
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
- cnt_q <= '0;
key_state_q <= '0;
idx_state_q <= '0;
data_state_q <= '0;
@@ -446,7 +457,6 @@
valid_q <= 1'b0;
digest_mode_q <= StandardMode;
end else begin
- cnt_q <= cnt_d;
valid_q <= valid_d;
digest_mode_q <= digest_mode_d;