blob: 59acff9ff2fb9b1841c871c14d826c43efe6f4f7 [file]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Life cycle signal decoder and sender module.
module lc_ctrl_signal_decode
import lc_ctrl_pkg::*;
import lc_ctrl_state_pkg::*;
#(
// Random netlist constants
// SCRAP, RAW, TEST_LOCKED*, INVALID
parameter lc_keymgr_div_t RndCnstLcKeymgrDivInvalid = LcKeymgrDivWidth'(0),
// TEST_UNLOCKED*, DEV, RMA
parameter lc_keymgr_div_t RndCnstLcKeymgrDivTestDevRma = LcKeymgrDivWidth'(1),
// PROD, PROD_END
parameter lc_keymgr_div_t RndCnstLcKeymgrDivProduction = LcKeymgrDivWidth'(2)
) (
input clk_i,
input rst_ni,
// Life cycle state vector.
input logic lc_state_valid_i,
input lc_state_e lc_state_i,
input fsm_state_e fsm_state_i,
input lc_tx_t secrets_valid_i,
// Local life cycle signal
output lc_tx_t lc_raw_test_rma_o,
// Life cycle broadcast outputs.
output lc_tx_t lc_dft_en_o,
output lc_tx_t lc_nvm_debug_en_o,
output lc_tx_t lc_hw_debug_en_o,
output lc_tx_t lc_cpu_en_o,
output lc_tx_t lc_creator_seed_sw_rw_en_o,
output lc_tx_t lc_owner_seed_sw_rw_en_o,
output lc_tx_t lc_iso_part_sw_rd_en_o,
output lc_tx_t lc_iso_part_sw_wr_en_o,
output lc_tx_t lc_seed_hw_rd_en_o,
output lc_tx_t lc_keymgr_en_o,
output lc_tx_t lc_escalate_en_o,
// State group diversification value for keymgr
output lc_keymgr_div_t lc_keymgr_div_o
);
//////////////////////////
// Signal Decoder Logic //
//////////////////////////
lc_tx_t lc_raw_test_rma;
lc_tx_t lc_dft_en, lc_nvm_debug_en, lc_hw_debug_en, lc_cpu_en, lc_keymgr_en, lc_escalate_en;
lc_tx_t lc_creator_seed_sw_rw_en, lc_owner_seed_sw_rw_en, lc_iso_part_sw_rd_en;
lc_tx_t lc_iso_part_sw_wr_en, lc_seed_hw_rd_en;
lc_keymgr_div_t lc_keymgr_div_d, lc_keymgr_div_q;
always_comb begin : p_lc_signal_decode
// Life cycle control signal defaults
lc_raw_test_rma = Off;
lc_dft_en = Off;
lc_nvm_debug_en = Off;
lc_hw_debug_en = Off;
lc_cpu_en = Off;
lc_creator_seed_sw_rw_en = Off;
lc_owner_seed_sw_rw_en = Off;
lc_iso_part_sw_rd_en = Off;
lc_iso_part_sw_wr_en = Off;
lc_seed_hw_rd_en = Off;
lc_keymgr_en = Off;
// This ensures that once escalation has been triggered, it cannot go back to Off.
lc_escalate_en = lc_tx_or_hi(Off, lc_escalate_en_o);
// Set to invalid diversification value by default.
lc_keymgr_div_d = RndCnstLcKeymgrDivInvalid;
unique case (fsm_state_i)
///////////////////////////////////////////////////////////////////
// Don't broadcast anything in this state.
ResetSt: ;
///////////////////////////////////////////////////////////////////
// Broadcasting of most signals is only enabled during the following life cycle states.
IdleSt,
ClkMuxSt,
CntIncrSt,
CntProgSt,
TransCheckSt,
FlashRmaSt,
TokenHashSt,
TokenCheck0St,
TokenCheck1St,
TransProgSt: begin
if (lc_state_valid_i) begin
unique case (lc_state_i)
///////////////////////////////////////////////////////////////////
// Only enable life cycle TAP register for OTP test mechanisms.
LcStRaw,
LcStTestLocked0,
LcStTestLocked1,
LcStTestLocked2,
LcStTestLocked3,
LcStTestLocked4,
LcStTestLocked5,
LcStTestLocked6: begin
lc_raw_test_rma = On;
end
///////////////////////////////////////////////////////////////////
// Enable DFT and debug functionality, including the CPU in the
// test unlocked states.
LcStTestUnlocked0,
LcStTestUnlocked1,
LcStTestUnlocked2,
LcStTestUnlocked3,
LcStTestUnlocked4,
LcStTestUnlocked5,
LcStTestUnlocked6: begin
lc_raw_test_rma = On;
lc_dft_en = On;
lc_nvm_debug_en = On;
lc_hw_debug_en = On;
lc_cpu_en = On;
lc_iso_part_sw_wr_en = On;
lc_keymgr_div_d = RndCnstLcKeymgrDivTestDevRma;
end
///////////////////////////////////////////////////////////////////
// This is the last TEST_UNLOCKED state. The same feature set is enabled
// as in the other TEST_UNLOCKED states above, except for NVM debug en,
// which is disabled in this state.
LcStTestUnlocked7: begin
lc_raw_test_rma = On;
lc_dft_en = On;
lc_hw_debug_en = On;
lc_cpu_en = On;
lc_iso_part_sw_wr_en = On;
lc_keymgr_div_d = RndCnstLcKeymgrDivTestDevRma;
end
///////////////////////////////////////////////////////////////////
// Enable production functions
LcStProd,
LcStProdEnd: begin
lc_cpu_en = On;
lc_keymgr_en = On;
lc_owner_seed_sw_rw_en = On;
lc_iso_part_sw_wr_en = On;
lc_iso_part_sw_rd_en = On;
lc_keymgr_div_d = RndCnstLcKeymgrDivProduction;
// Only allow provisioning if the device has not yet been personalized.
// If secrets_valid_i is set to ON, we output OFF.
// Note that we can convert ON to OFF with a bitwise inversion due to the encoding.
lc_creator_seed_sw_rw_en = lc_tx_t'(~secrets_valid_i);
// Only allow hardware to consume the seeds once personalized.
// If secrets_valid_i is set to ON, we output ON.
lc_seed_hw_rd_en = secrets_valid_i;
end
///////////////////////////////////////////////////////////////////
// Similar functions as PROD, with the following differences:
// - hardware debug functionality (CPU TAP) is enabled,
// - access to the isolated flash partition is disabled.
LcStDev: begin
lc_hw_debug_en = On;
lc_cpu_en = On;
lc_keymgr_en = On;
lc_owner_seed_sw_rw_en = On;
lc_iso_part_sw_wr_en = On;
lc_keymgr_div_d = RndCnstLcKeymgrDivTestDevRma;
// Only allow provisioning if the device has not yet been personalized.
// If secrets_valid_i is set to ON, we output OFF.
// Note that we can convert ON to OFF with a bitwise inversion due to the encoding.
lc_creator_seed_sw_rw_en = lc_tx_t'(~secrets_valid_i);
// Only allow hardware to consume the seeds once personalized.
// If secrets_valid_i is set to ON, we output ON.
lc_seed_hw_rd_en = secrets_valid_i;
end
///////////////////////////////////////////////////////////////////
// Enable all test and production functions.
LcStRma: begin
lc_raw_test_rma = On;
lc_dft_en = On;
lc_nvm_debug_en = On;
lc_hw_debug_en = On;
lc_cpu_en = On;
lc_keymgr_en = On;
lc_creator_seed_sw_rw_en = On;
lc_owner_seed_sw_rw_en = On;
lc_iso_part_sw_wr_en = On;
lc_iso_part_sw_rd_en = On;
lc_seed_hw_rd_en = On;
lc_keymgr_div_d = RndCnstLcKeymgrDivTestDevRma;
end
///////////////////////////////////////////////////////////////////
// Invalid or scrapped life cycle state, make sure the escalation
// signal is also asserted in this case.
default: begin
lc_escalate_en = On;
end
endcase // lc_state_i
end else begin
lc_escalate_en = On;
end
end
///////////////////////////////////////////////////////////////////
// Post-transition state. Behaves similarly to the virtual scrap
// states below, with the exception that escalate_en is NOT asserted,
// since that could trigger unwanted alerts / escalations and system resets.
PostTransSt: ;
///////////////////////////////////////////////////////////////////
// Virtual scrap states, make sure the escalation signal is
// also asserted in this case.
ScrapSt,
EscalateSt,
InvalidSt: begin
lc_escalate_en = On;
end
default: begin
lc_escalate_en = On;
end
endcase // fsm_state_i
end
/////////////////////////////////
// Control signal output flops //
/////////////////////////////////
prim_lc_sender u_prim_lc_sender_raw_test_rma (
.clk_i,
.rst_ni,
.lc_en_i(lc_raw_test_rma),
.lc_en_o(lc_raw_test_rma_o)
);
prim_lc_sender u_prim_lc_sender_dft_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_dft_en),
.lc_en_o(lc_dft_en_o)
);
prim_lc_sender u_prim_lc_sender_nvm_debug_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_nvm_debug_en),
.lc_en_o(lc_nvm_debug_en_o)
);
prim_lc_sender u_prim_lc_sender_hw_debug_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_hw_debug_en),
.lc_en_o(lc_hw_debug_en_o)
);
prim_lc_sender u_prim_lc_sender_cpu_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_cpu_en),
.lc_en_o(lc_cpu_en_o)
);
prim_lc_sender u_prim_lc_sender_creator_seed_sw_rw_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_creator_seed_sw_rw_en),
.lc_en_o(lc_creator_seed_sw_rw_en_o)
);
prim_lc_sender u_prim_lc_sender_owner_seed_sw_rw_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_owner_seed_sw_rw_en),
.lc_en_o(lc_owner_seed_sw_rw_en_o)
);
prim_lc_sender u_prim_lc_sender_iso_part_sw_rd_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_iso_part_sw_rd_en),
.lc_en_o(lc_iso_part_sw_rd_en_o)
);
prim_lc_sender u_prim_lc_sender_iso_part_sw_wr_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_iso_part_sw_wr_en),
.lc_en_o(lc_iso_part_sw_wr_en_o)
);
prim_lc_sender u_prim_lc_sender_seed_hw_rd_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_seed_hw_rd_en),
.lc_en_o(lc_seed_hw_rd_en_o)
);
prim_lc_sender u_prim_lc_sender_keymgr_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_keymgr_en),
.lc_en_o(lc_keymgr_en_o)
);
prim_lc_sender u_prim_lc_sender_escalate_en (
.clk_i,
.rst_ni,
.lc_en_i(lc_escalate_en),
.lc_en_o(lc_escalate_en_o)
);
assign lc_keymgr_div_o = lc_keymgr_div_q;
prim_flop #(
.Width(LcKeymgrDivWidth),
.ResetValue(RndCnstLcKeymgrDivInvalid)
) u_prim_flop_keymgr_div (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.d_i ( lc_keymgr_div_d ),
.q_o ( lc_keymgr_div_q )
);
////////////////
// Assertions //
////////////////
// Need to make sure that the random netlist constants
// are unique.
`ASSERT_INIT(LcKeymgrDivUnique0_A,
!(RndCnstLcKeymgrDivInvalid inside {RndCnstLcKeymgrDivTestDevRma,
RndCnstLcKeymgrDivProduction}))
`ASSERT_INIT(LcKeymgrDivUnique1_A, RndCnstLcKeymgrDivProduction != RndCnstLcKeymgrDivTestDevRma)
`ASSERT(SignalsAreOffWhenNotEnabled_A,
!lc_state_valid_i
|=>
lc_raw_test_rma_o == Off &&
lc_dft_en_o == Off &&
lc_nvm_debug_en_o == Off &&
lc_hw_debug_en_o == Off &&
lc_cpu_en_o == Off &&
lc_creator_seed_sw_rw_en_o == Off &&
lc_owner_seed_sw_rw_en_o == Off &&
lc_iso_part_sw_rd_en_o == Off &&
lc_iso_part_sw_wr_en_o == Off &&
lc_seed_hw_rd_en_o == Off &&
lc_keymgr_en_o == Off &&
lc_dft_en_o == Off &&
lc_keymgr_div_o == RndCnstLcKeymgrDivInvalid)
`ASSERT(FsmInScrap_A,
!(fsm_state_i inside {ResetSt,
TransProgSt,
IdleSt,
ClkMuxSt,
CntIncrSt,
CntProgSt,
TransCheckSt,
FlashRmaSt,
TokenHashSt,
TokenCheck0St,
TokenCheck1St,
PostTransSt})
|=>
lc_escalate_en_o == On)
`ASSERT(StateInScrap_A,
lc_state_valid_i &&
fsm_state_i inside {IdleSt,
ClkMuxSt,
CntIncrSt,
CntProgSt,
TransCheckSt,
FlashRmaSt,
TokenHashSt,
TokenCheck0St,
TokenCheck1St} &&
!(lc_state_i inside {LcStRaw,
LcStTestUnlocked0,
LcStTestUnlocked1,
LcStTestUnlocked2,
LcStTestUnlocked3,
LcStTestUnlocked4,
LcStTestUnlocked5,
LcStTestUnlocked6,
LcStTestUnlocked7,
LcStTestLocked0,
LcStTestLocked1,
LcStTestLocked2,
LcStTestLocked3,
LcStTestLocked4,
LcStTestLocked5,
LcStTestLocked6,
LcStDev,
LcStProd,
LcStProdEnd,
LcStRma})
|=>
lc_escalate_en_o == On)
endmodule : lc_ctrl_signal_decode