[lc_ctrl] Add first cut implementation
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
index 1f024c0..85ca004 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
@@ -5,6 +5,76 @@
package lc_ctrl_pkg;
+ import prim_util_pkg::vbits;
+
+ // TODO: need to generate these randomly, based on ECC
+ // polynomial used inside the OTP macro.
+ // The A/B values are used for the encoded LC state.
+ parameter logic [15:0] A0 = 16'h0000;
+ parameter logic [15:0] A1 = 16'h0000;
+ parameter logic [15:0] A2 = 16'h0000;
+ parameter logic [15:0] A3 = 16'h0000;
+ parameter logic [15:0] A4 = 16'h0000;
+ parameter logic [15:0] A5 = 16'h0000;
+ parameter logic [15:0] A6 = 16'h0000;
+ parameter logic [15:0] A7 = 16'h0000;
+ parameter logic [15:0] A8 = 16'h0000;
+ parameter logic [15:0] A9 = 16'h0000;
+ parameter logic [15:0] A10 = 16'h0000;
+ parameter logic [15:0] A11 = 16'h0000;
+
+ parameter logic [15:0] B0 = 16'hFFFF;
+ parameter logic [15:0] B1 = 16'hFFFF;
+ parameter logic [15:0] B2 = 16'hFFFF;
+ parameter logic [15:0] B3 = 16'hFFFF;
+ parameter logic [15:0] B4 = 16'hFFFF;
+ parameter logic [15:0] B5 = 16'hFFFF;
+ parameter logic [15:0] B6 = 16'hFFFF;
+ parameter logic [15:0] B7 = 16'hFFFF;
+ parameter logic [15:0] B8 = 16'hFFFF;
+ parameter logic [15:0] B9 = 16'hFFFF;
+ parameter logic [15:0] B10 = 16'hFFFF;
+ parameter logic [15:0] B11 = 16'hFFFF;
+
+ // The C/D values are used for the encoded LC transition counter.
+ parameter logic [15:0] C0 = 16'h0000;
+ parameter logic [15:0] C1 = 16'h0000;
+ parameter logic [15:0] C2 = 16'h0000;
+ parameter logic [15:0] C3 = 16'h0000;
+ parameter logic [15:0] C4 = 16'h0000;
+ parameter logic [15:0] C5 = 16'h0000;
+ parameter logic [15:0] C6 = 16'h0000;
+ parameter logic [15:0] C7 = 16'h0000;
+ parameter logic [15:0] C8 = 16'h0000;
+ parameter logic [15:0] C9 = 16'h0000;
+ parameter logic [15:0] C10 = 16'h0000;
+ parameter logic [15:0] C11 = 16'h0000;
+ parameter logic [15:0] C12 = 16'h0000;
+ parameter logic [15:0] C13 = 16'h0000;
+ parameter logic [15:0] C14 = 16'h0000;
+ parameter logic [15:0] C15 = 16'h0000;
+
+ parameter logic [15:0] D0 = 16'hFFFF;
+ parameter logic [15:0] D1 = 16'hFFFF;
+ parameter logic [15:0] D2 = 16'hFFFF;
+ parameter logic [15:0] D3 = 16'hFFFF;
+ parameter logic [15:0] D4 = 16'hFFFF;
+ parameter logic [15:0] D5 = 16'hFFFF;
+ parameter logic [15:0] D6 = 16'hFFFF;
+ parameter logic [15:0] D7 = 16'hFFFF;
+ parameter logic [15:0] D8 = 16'hFFFF;
+ parameter logic [15:0] D9 = 16'hFFFF;
+ parameter logic [15:0] D10 = 16'hFFFF;
+ parameter logic [15:0] D11 = 16'hFFFF;
+ parameter logic [15:0] D12 = 16'hFFFF;
+ parameter logic [15:0] D13 = 16'hFFFF;
+ parameter logic [15:0] D14 = 16'hFFFF;
+ parameter logic [15:0] D15 = 16'hFFFF;
+
+ // The E/F values are used for the encoded ID state.
+ parameter logic [15:0] E0 = 16'h0000;
+ parameter logic [15:0] F0 = 16'hFFFF;
+
/////////////////////////////////
// General Typedefs and Params //
/////////////////////////////////
@@ -15,30 +85,108 @@
parameter int LcStateWidth = NumLcStateValues * LcValueWidth;
parameter int NumLcCountValues = 16;
parameter int LcCountWidth = NumLcCountValues * LcValueWidth;
+ parameter int NumLcStates = 13;
+ parameter int DecLcStateWidth = vbits(NumLcStates);
+ parameter int DecLcCountWidth = vbits(NumLcCountValues+1);
+ parameter int LcIdStateWidth = LcValueWidth;
+ parameter int DecLcIdStateWidth = 2;
- typedef enum logic [LcValueWidth-1:0] {
- Blk = 16'h0000, // blank
- Set = 16'hF5FA // programmed
- } lc_value_e;
+ typedef logic [LcTokenWidth-1:0] lc_token_t;
+ // TODO: make this secret and generate randomly, given a specific ECC polynomial.
typedef enum logic [LcStateWidth-1:0] {
// Halfword idx : 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
- LcStRaw = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk},
- LcStTestUnlocked0 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set},
- LcStTestLocked0 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set},
- LcStTestUnlocked1 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set},
- LcStTestLocked1 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set},
- LcStTestUnlocked2 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set},
- LcStTestLocked2 = {Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set},
- LcStTestUnlocked3 = {Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
- LcStDev = {Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set, Set},
- LcStProd = {Blk, Blk, Blk, Set, Blk, Set, Set, Set, Set, Set, Set, Set},
- LcStProdEnd = {Blk, Blk, Set, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
- LcStRma = {Set, Set, Blk, Set, Set, Set, Set, Set, Set, Set, Set, Set},
- LcStScrap = {Set, Set, Set, Set, Set, Set, Set, Set, Set, Set, Set, Set}
+ LcStRaw = '0,
+ LcStTestUnlocked0 = {A11, A10, A9, A8, A7, A6, A5, A4, A3, A2, A1, B0},
+ LcStTestLocked0 = {A11, A10, A9, A8, A7, A6, A5, A4, A3, A2, B1, B0},
+ LcStTestUnlocked1 = {A11, A10, A9, A8, A7, A6, A5, A4, A3, B2, B1, B0},
+ LcStTestLocked1 = {A11, A10, A9, A8, A7, A6, A5, A4, B3, B2, B1, B0},
+ LcStTestUnlocked2 = {A11, A10, A9, A8, A7, A6, A5, B4, B3, B2, B1, B0},
+ LcStTestLocked2 = {A11, A10, A9, A8, A7, A6, B5, B4, B3, B2, B1, B0},
+ LcStTestUnlocked3 = {A11, A10, A9, A8, A7, B6, B5, B4, B3, B2, B1, B0},
+ LcStDev = {A11, A10, A9, A8, B7, B6, B5, B4, B3, B2, B1, B0},
+ LcStProd = {A11, A10, A9, B8, A7, B6, B5, B4, B3, B2, B1, B0},
+ LcStProdEnd = {A11, A10, B9, A8, A7, B6, B5, B4, B3, B2, B1, B0},
+ LcStRma = {B11, B10, A9, B8, B7, B6, B5, B4, B3, B2, B1, B0},
+ LcStScrap = {B11, B10, B9, B8, B7, B6, B5, B4, B3, B2, B1, B0}
} lc_state_e;
- typedef lc_value_e [NumLcCountValues-1:0] lc_cnt_t;
+ // Decoded life cycle state, used to interface with CSRs and TAP.
+ typedef enum logic [DecLcStateWidth-1:0] {
+ DecLcStRaw = 4'h0,
+ DecLcStTestUnlocked0 = 4'h1,
+ DecLcStTestLocked0 = 4'h2,
+ DecLcStTestUnlocked1 = 4'h3,
+ DecLcStTestLocked1 = 4'h4,
+ DecLcStTestUnlocked2 = 4'h5,
+ DecLcStTestLocked2 = 4'h6,
+ DecLcStTestUnlocked3 = 4'h7,
+ DecLcStDev = 4'h8,
+ DecLcStProd = 4'h9,
+ DecLcStProdEnd = 4'hA,
+ DecLcStRma = 4'hB,
+ DecLcStScrap = 4'hC,
+ DecLcStPostTrans = 4'hD,
+ DecLcStEscalate = 4'hE,
+ DecLcStInvalid = 4'hF
+ } dec_lc_state_e;
+
+ typedef enum logic [LcIdStateWidth-1:0] {
+ LcIdBlank = E0,
+ LcIdPersonalized = F0
+ } lc_id_state_e;
+
+ typedef enum logic [DecLcIdStateWidth-1:0] {
+ DecLcIdBlank = 2'd0,
+ DecLcIdPersonalized = 2'd1,
+ DecLcIdInvalid = 2'd2
+ } dec_lc_id_state_e;
+
+ typedef enum logic [LcCountWidth-1:0] {
+ LcCntRaw = '0,
+ LcCnt1 = {C15, C14, C13, C12, C11, C10, C9, C8, C7, C6, C5, C4, C3, C2, C1, D0},
+ LcCnt2 = {C15, C14, C13, C12, C11, C10, C9, C8, C7, C6, C5, C4, C3, C2, D1, D0},
+ LcCnt3 = {C15, C14, C13, C12, C11, C10, C9, C8, C7, C6, C5, C4, C3, D2, D1, D0},
+ LcCnt4 = {C15, C14, C13, C12, C11, C10, C9, C8, C7, C6, C5, C4, D3, D2, D1, D0},
+ LcCnt5 = {C15, C14, C13, C12, C11, C10, C9, C8, C7, C6, C5, D4, D3, D2, D1, D0},
+ LcCnt6 = {C15, C14, C13, C12, C11, C10, C9, C8, C7, C6, D5, D4, D3, D2, D1, D0},
+ LcCnt7 = {C15, C14, C13, C12, C11, C10, C9, C8, C7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt8 = {C15, C14, C13, C12, C11, C10, C9, C8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt9 = {C15, C14, C13, C12, C11, C10, C9, D8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt10 = {C15, C14, C13, C12, C11, C10, D9, D8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt11 = {C15, C14, C13, C12, C11, D10, D9, D8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt12 = {C15, C14, C13, C12, D11, D10, D9, D8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt13 = {C15, C14, C13, D12, D11, D10, D9, D8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt14 = {C15, C14, D13, D12, D11, D10, D9, D8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt15 = {C15, D14, D13, D12, D11, D10, D9, D8, D7, D6, D5, D4, D3, D2, D1, D0},
+ LcCnt16 = {D15, D14, D13, D12, D11, D10, D9, D8, D7, D6, D5, D4, D3, D2, D1, D0}
+ } lc_cnt_e;
+
+ typedef logic [DecLcCountWidth-1:0] dec_lc_cnt_t;
+
+
+ ///////////////////////////////////////
+ // Netlist Constants (Hashed Tokens) //
+ ///////////////////////////////////////
+
+ parameter int NumTokens = 6;
+ parameter int TokenIdxWidth = vbits(NumTokens);
+ typedef enum logic [TokenIdxWidth-1:0] {
+ // This is the index for the hashed all-zero constant.
+ // All unconditional transitions use this token.
+ ZeroTokenIdx = 3'h0,
+ RawUnlockTokenIdx = 3'h1,
+ TestUnlockTokenIdx = 3'h2,
+ TestExitTokenIdx = 3'h3,
+ RmaTokenIdx = 3'h4,
+ // This is the index for an all-zero value (i.e., hashed value = '0).
+ // This is used as an additional blocker for some invalid state transition edges.
+ InvalidTokenIdx = 3'h5
+ } token_idx_e;
+
+ // TODO: precompute these values (probably have to do that in OTP at elab time).
+ parameter logic [TokenIdxWidth-1:0] RawUnlockTokenHashed = '0;
+ parameter logic [TokenIdxWidth-1:0] AllZeroTokenHashed = '0;
////////////////////////////////
// Typedefs for LC Interfaces //
@@ -50,10 +198,149 @@
Off = 4'b0101
} lc_tx_e;
- typedef struct packed {
- lc_tx_e state;
- } lc_tx_t;
+ typedef lc_tx_e lc_tx_t;
parameter lc_tx_t LC_TX_DEFAULT = Off;
+ parameter int RmaSeedWidth = 32;
+ typedef logic [RmaSeedWidth-1:0] lc_flash_rma_seed_t;
+
+ ////////////////////
+ // Main FSM State //
+ ////////////////////
+
+ // Encoding generated with:
+ // $ ./sparse-fsm-encode.py -d 5 -m 14 -n 16 \
+ // -s 2934212379 --language=sv
+ //
+ // Hamming distance histogram:
+ //
+ // 0: --
+ // 1: --
+ // 2: --
+ // 3: --
+ // 4: --
+ // 5: |||||| (6.59%)
+ // 6: |||||||||| (10.99%)
+ // 7: |||||||||||||||| (17.58%)
+ // 8: |||||||||||||||||||| (20.88%)
+ // 9: |||||||||||||||| (17.58%)
+ // 10: |||||||||||||| (15.38%)
+ // 11: |||||| (6.59%)
+ // 12: ||| (3.30%)
+ // 13: | (1.10%)
+ // 14: --
+ // 15: --
+ // 16: --
+ //
+ // Minimum Hamming distance: 5
+ // Maximum Hamming distance: 13
+ //
+ localparam int FsmStateWidth = 16;
+ typedef enum logic [FsmStateWidth-1:0] {
+ ResetSt = 16'b1100000001111011,
+ IdleSt = 16'b1111011010111100,
+ ClkMuxSt = 16'b0000011110101101,
+ CntIncrSt = 16'b1100111011001001,
+ CntProgSt = 16'b0011001111000111,
+ TransCheckSt = 16'b0000110001010100,
+ TokenHashSt = 16'b1110100010001111,
+ FlashRmaSt = 16'b0110111010110000,
+ TokenCheck0St = 16'b0010000011000000,
+ TokenCheck1St = 16'b1101010101101111,
+ TransProgSt = 16'b1000000110101011,
+ PostTransSt = 16'b0110110100101100,
+ EscalateSt = 16'b1010100001010001,
+ InvalidSt = 16'b1011110110011011
+ } fsm_state_e;
+
+ ///////////////////////////////////////////
+ // Manufacturing State Transition Matrix //
+ ///////////////////////////////////////////
+
+ // The token index matrix below encodes 1) which transition edges are valid and 2) which token
+ // to use for a given transition edge. Note that unconditional but otherwise valid transitions
+ // are assigned the ZeroTokenIdx, whereas invalid transitions are assigned an InvalidTokenIdx.
+ parameter token_idx_e [NumLcStates-1:0][NumLcStates-1:0] TransTokenIdxMatrix = {
+ // SCRAP
+ {13{InvalidTokenIdx}}, // -> TEST_LOCKED0-2, TEST_UNLOCKED0-3, DEV, PROD, PROD_END, RMA, SCRAP
+ // RMA
+ ZeroTokenIdx, // -> SCRAP
+ {12{InvalidTokenIdx}}, // -> TEST_LOCKED0-2, TEST_UNLOCKED0-3, DEV, PROD, PROD_END, RMA
+ // PROD_END
+ ZeroTokenIdx, // -> SCRAP
+ {12{InvalidTokenIdx}}, // -> TEST_LOCKED0-2, TEST_UNLOCKED0-3, DEV, PROD, PROD_END, RMA
+ // PROD
+ ZeroTokenIdx, // -> SCRAP
+ RmaTokenIdx, // -> RMA
+ {11{InvalidTokenIdx}}, // -> TEST_LOCKED0-2, TEST_UNLOCKED0-3, DEV, PROD, PROD_END
+ // DEV
+ ZeroTokenIdx, // -> SCRAP
+ RmaTokenIdx, // -> RMA
+ {11{InvalidTokenIdx}}, // -> TEST_LOCKED0-2, TEST_UNLOCKED0-3, DEV, PROD, PROD_END
+ // TEST_UNLOCKED2
+ {2{ZeroTokenIdx}}, // -> SCRAP, RMA
+ {3{TestExitTokenIdx}}, // -> PROD, PROD_END, DEV
+ {8{InvalidTokenIdx}}, // -> TEST_LOCKED0-2, TEST_UNLOCKED0-3, RAW
+ // TEST_LOCKED2
+ ZeroTokenIdx, // -> SCRAP
+ InvalidTokenIdx, // -> RMA
+ {3{TestExitTokenIdx}}, // -> PROD, PROD_END, DEV
+ TestUnlockTokenIdx, // -> TEST_UNLOCKED3
+ {7{InvalidTokenIdx}}, // -> TEST_LOCKED0-2, TEST_UNLOCKED0-2, RAW
+ // TEST_UNLOCKED2
+ {2{ZeroTokenIdx}}, // -> SCRAP, RMA
+ {3{TestExitTokenIdx}}, // -> PROD, PROD_END, DEV
+ InvalidTokenIdx, // -> TEST_UNLOCKED3
+ ZeroTokenIdx, // -> TEST_LOCKED2
+ {6{InvalidTokenIdx}}, // -> TEST_LOCKED0-1, TEST_UNLOCKED0-2, RAW
+ // TEST_LOCKED1
+ ZeroTokenIdx, // -> SCRAP
+ InvalidTokenIdx, // -> RMA
+ {3{TestExitTokenIdx}}, // -> PROD, PROD_END, DEV
+ TestUnlockTokenIdx, // -> TEST_UNLOCKED3
+ InvalidTokenIdx , // -> TEST_LOCKED2
+ TestUnlockTokenIdx, // -> TEST_UNLOCKED2
+ {5{InvalidTokenIdx}}, // -> TEST_LOCKED0-1, TEST_UNLOCKED0-1, RAW
+ // TEST_UNLOCKED1
+ {2{ZeroTokenIdx}}, // -> SCRAP, RMA
+ {3{TestExitTokenIdx}}, // -> PROD, PROD_END, DEV
+ InvalidTokenIdx, // -> TEST_UNLOCKED3
+ ZeroTokenIdx, // -> TEST_LOCKED2
+ InvalidTokenIdx, // -> TEST_UNLOCKED2
+ ZeroTokenIdx, // -> TEST_LOCKED1
+ {4{InvalidTokenIdx}}, // -> TEST_LOCKED0, TEST_UNLOCKED0-1, RAW
+ // TEST_LOCKED0
+ ZeroTokenIdx, // -> SCRAP
+ InvalidTokenIdx, // -> RMA
+ {3{TestExitTokenIdx}}, // -> PROD, PROD_END, DEV
+ TestUnlockTokenIdx, // -> TEST_UNLOCKED3
+ InvalidTokenIdx, // -> TEST_LOCKED2
+ TestUnlockTokenIdx, // -> TEST_UNLOCKED2
+ InvalidTokenIdx, // -> TEST_LOCKED1
+ TestUnlockTokenIdx, // -> TEST_UNLOCKED1
+ {3{InvalidTokenIdx}}, // -> TEST_LOCKED0, TEST_UNLOCKED0, RAW
+ // TEST_UNLOCKED0
+ {2{ZeroTokenIdx}}, // -> SCRAP, RMA
+ {3{TestExitTokenIdx}}, // -> PROD, PROD_END, DEV
+ InvalidTokenIdx, // -> TEST_UNLOCKED3
+ ZeroTokenIdx, // -> TEST_LOCKED2
+ InvalidTokenIdx, // -> TEST_UNLOCKED2
+ ZeroTokenIdx, // -> TEST_LOCKED1
+ InvalidTokenIdx, // -> TEST_UNLOCKED1
+ ZeroTokenIdx, // -> TEST_LOCKED0
+ {2{InvalidTokenIdx}}, // -> TEST_UNLOCKED0, RAW
+ // RAW
+ ZeroTokenIdx, // -> SCRAP
+ {4{InvalidTokenIdx}}, // -> RMA, PROD, PROD_END, DEV
+ RawUnlockTokenIdx, // -> TEST_UNLOCKED3
+ InvalidTokenIdx, // -> TEST_LOCKED2
+ RawUnlockTokenIdx, // -> TEST_UNLOCKED2
+ InvalidTokenIdx, // -> TEST_LOCKED1
+ RawUnlockTokenIdx, // -> TEST_UNLOCKED1
+ InvalidTokenIdx, // -> TEST_LOCKED0
+ RawUnlockTokenIdx, // -> TEST_UNLOCKED0
+ InvalidTokenIdx // -> RAW
+ };
+
endpackage : lc_ctrl_pkg