| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| |
| `include "prim_assert.sv" |
| |
| package lc_ctrl_pkg; |
| |
| import prim_util_pkg::vbits; |
| import lc_ctrl_state_pkg::*; |
| |
| /////////////////////////////////////// |
| // 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; |
| |
| parameter int TokenMuxBits = 2**TokenIdxWidth*LcTokenWidth; |
| typedef logic [TokenMuxBits-1:0] lc_token_mux_t; |
| |
| //////////////////////////////// |
| // Typedefs for LC Interfaces // |
| //////////////////////////////// |
| |
| parameter int TxWidth = 4; |
| |
| // Note that changing this encoding has implications on isolation cell |
| // values in RTL. Do not change this unless absolutely needed. |
| typedef enum logic [TxWidth-1:0] { |
| On = 4'b0101, |
| Off = 4'b1010 |
| } lc_tx_t; |
| parameter lc_tx_t LC_TX_DEFAULT = lc_tx_t'(Off); |
| |
| parameter int RmaSeedWidth = 32; |
| typedef logic [RmaSeedWidth-1:0] lc_flash_rma_seed_t; |
| parameter lc_flash_rma_seed_t LC_FLASH_RMA_SEED_DEFAULT = '0; |
| |
| parameter int LcKeymgrDivWidth = 128; |
| typedef logic [LcKeymgrDivWidth-1:0] lc_keymgr_div_t; |
| |
| typedef struct packed { |
| logic [lc_ctrl_reg_pkg::HwRevFieldWidth-1:0] chip_gen; |
| logic [lc_ctrl_reg_pkg::HwRevFieldWidth-1:0] chip_rev; |
| } lc_hw_rev_t; |
| |
| ///////////////////////////////////////////// |
| // Helper Functions for Life Cycle Signals // |
| ///////////////////////////////////////////// |
| |
| // This is a prerequisite for the multibit functions below to work. |
| `ASSERT_STATIC_IN_PACKAGE(CheckLcTxValsComplementary_A, On == ~Off) |
| // Check for bit-width matching between lc_tx_t and mubi4_t |
| `ASSERT_STATIC_IN_PACKAGE(LcMuBiWidthCheck_A, $bits(TxWidth) == $bits(prim_mubi_pkg::MuBi4Width)) |
| |
| // Convert a life cycle signal to mubi4 |
| // If in the future other versions are desired, this should really be |
| // moved to prim_mubi_pkg |
| // |
| // The On ^ MuBi4True determines the bit differences between |
| // an lc_ctrl_pkg::On and prim_mubi_pkg::MuBi4True. |
| // Once the required inversions are determined, it is then applied |
| // to the incoming value. If the incoming value is true, it will |
| // appropriately flip to the correct MuBiValue. |
| // Since the false value is always complement of the true value, |
| // this mechanism will also work for the other polarity. |
| function automatic prim_mubi_pkg::mubi4_t lc_to_mubi4(lc_tx_t val); |
| return prim_mubi_pkg::mubi4_t'(val ^ (On ^ prim_mubi_pkg::MuBi4True)); |
| endfunction : lc_to_mubi4 |
| |
| function automatic lc_tx_t mubi4_to_lc(prim_mubi_pkg::mubi4_t val); |
| return lc_tx_t'(val ^ (prim_mubi_pkg::MuBi4True ^ On)); |
| endfunction : mubi4_to_lc |
| |
| // same function as above, but for an input that is MuBi4True, return Off |
| // for an input that is MuBi4False, return On |
| function automatic lc_tx_t mubi4_to_lc_inv(prim_mubi_pkg::mubi4_t val); |
| return lc_tx_t'(val ^ (prim_mubi_pkg::MuBi4True ^ Off)); |
| endfunction : mubi4_to_lc_inv |
| |
| // Test whether the value is supplied is one of the valid enumerations |
| function automatic logic lc_tx_test_invalid(lc_tx_t val); |
| return ~(val inside {On, Off}); |
| endfunction : lc_tx_test_invalid |
| |
| // Convert a 1 input value to a lc_tx output |
| function automatic lc_tx_t lc_tx_bool_to_lc_tx(logic val); |
| return (val ? On : Off); |
| endfunction : lc_tx_bool_to_lc_tx |
| |
| // Test whether the multibit value signals an "enabled" condition. |
| // The strict version of this function requires |
| // the multibit value to equal True. |
| function automatic logic lc_tx_test_true_strict(lc_tx_t val); |
| return On == val; |
| endfunction : lc_tx_test_true_strict |
| |
| // Test whether the multibit value signals a "disabled" condition. |
| // The strict version of this function requires |
| // the multibit value to equal False. |
| function automatic logic lc_tx_test_false_strict(lc_tx_t val); |
| return Off == val; |
| endfunction : lc_tx_test_false_strict |
| |
| // Test whether the multibit value signals an "enabled" condition. |
| // The loose version of this function interprets all |
| // values other than False as "enabled". |
| function automatic logic lc_tx_test_true_loose(lc_tx_t val); |
| return Off != val; |
| endfunction : lc_tx_test_true_loose |
| |
| // Test whether the multibit value signals a "disabled" condition. |
| // The loose version of this function interprets all |
| // values other than True as "disabled". |
| function automatic logic lc_tx_test_false_loose(lc_tx_t val); |
| return On != val; |
| endfunction : lc_tx_test_false_loose |
| |
| |
| // Performs a logical OR operation between two multibit values. |
| // This treats "act" as logical 1, and all other values are |
| // treated as 0. Truth table: |
| // |
| // A | B | OUT |
| //------+------+----- |
| // !act | !act | !act |
| // act | !act | act |
| // !act | act | act |
| // act | act | act |
| // |
| // Note: due to the nature of the lc_tx_or() function, it is possible that two |
| // non-strictly "act" values may produce a strictly "act" value. If this is |
| // of concern, e.g. if the output is consumed with a strict check on "act", |
| // consider using the prim_lc_or_hardened primitive instead. |
| function automatic lc_tx_t lc_tx_or(lc_tx_t a, lc_tx_t b, lc_tx_t act); |
| logic [TxWidth-1:0] a_in, b_in, act_in, out; |
| a_in = a; |
| b_in = b; |
| act_in = act; |
| for (int k = 0; k < TxWidth; k++) begin |
| if (act_in[k]) begin |
| out[k] = a_in[k] || b_in[k]; |
| end else begin |
| out[k] = a_in[k] && b_in[k]; |
| end |
| end |
| return lc_tx_t'(out); |
| endfunction : lc_tx_or |
| |
| // Performs a logical AND operation between two multibit values. |
| // This treats "act" as logical 1, and all other values are |
| // treated as 0. Truth table: |
| // |
| // A | B | OUT |
| //------+------+----- |
| // !act | !act | !act |
| // act | !act | !act |
| // !act | act | !act |
| // act | act | act |
| // |
| // Noite: The lc_tx_and() function does not suffer from the strictness problem |
| // that the lc_tx_or function above does, since only one output value in the |
| // truth table is strictly "act". It can hence be used in most scenarios without issues. |
| // If however the lc_tx_and() function should be strictly rectifying (i.e., only |
| // output "act" or ~"act"), the prim_lc_and_hardened can be used. |
| function automatic lc_tx_t lc_tx_and(lc_tx_t a, lc_tx_t b, lc_tx_t act); |
| logic [TxWidth-1:0] a_in, b_in, act_in, out; |
| a_in = a; |
| b_in = b; |
| act_in = act; |
| for (int k = 0; k < TxWidth; k++) begin |
| if (act_in[k]) begin |
| out[k] = a_in[k] && b_in[k]; |
| end else begin |
| out[k] = a_in[k] || b_in[k]; |
| end |
| end |
| return lc_tx_t'(out); |
| endfunction : lc_tx_and |
| |
| // Performs a logical OR operation between two multibit values. |
| // This treats "True" as logical 1, and all other values are |
| // treated as 0. |
| function automatic lc_tx_t lc_tx_or_hi(lc_tx_t a, lc_tx_t b); |
| return lc_tx_or(a, b, On); |
| endfunction : lc_tx_or_hi |
| |
| // Performs a logical AND operation between two multibit values. |
| // This treats "True" as logical 1, and all other values are |
| // treated as 0. |
| function automatic lc_tx_t lc_tx_and_hi(lc_tx_t a, lc_tx_t b); |
| return lc_tx_and(a, b, On); |
| endfunction : lc_tx_and_hi |
| |
| // Performs a logical OR operation between two multibit values. |
| // This treats "False" as logical 1, and all other values are |
| // treated as 0. |
| function automatic lc_tx_t lc_tx_or_lo(lc_tx_t a, lc_tx_t b); |
| return lc_tx_or(a, b, Off); |
| endfunction : lc_tx_or_lo |
| |
| // Performs a logical AND operation between two multibit values. |
| // Tlos treats "False" as logical 1, and all other values are |
| // treated as 0. |
| function automatic lc_tx_t lc_tx_and_lo(lc_tx_t a, lc_tx_t b); |
| return lc_tx_and(a, b, Off); |
| endfunction : lc_tx_and_lo |
| |
| // Inverts the logical meaning of the multibit value. |
| function automatic lc_tx_t lc_tx_inv(lc_tx_t a); |
| return lc_tx_t'(~TxWidth'(a)); |
| endfunction : lc_tx_inv |
| |
| //////////////////// |
| // Main FSM State // |
| //////////////////// |
| |
| // SEC_CM: MAIN.FSM.SPARSE |
| // Encoding generated with: |
| // $ ./util/design/sparse-fsm-encode.py -d 5 -m 15 -n 16 \ |
| // -s 2934212379 --language=sv |
| // |
| // Hamming distance histogram: |
| // |
| // 0: -- |
| // 1: -- |
| // 2: -- |
| // 3: -- |
| // 4: -- |
| // 5: ||||||| (7.62%) |
| // 6: ||||||||| (9.52%) |
| // 7: |||||||||||||||| (17.14%) |
| // 8: |||||||||||||||||||| (20.95%) |
| // 9: ||||||||||||||||| (18.10%) |
| // 10: ||||||||||||| (14.29%) |
| // 11: |||||| (6.67%) |
| // 12: ||| (3.81%) |
| // 13: | (1.90%) |
| // 14: -- |
| // 15: -- |
| // 16: -- |
| // |
| // Minimum Hamming distance: 5 |
| // Maximum Hamming distance: 13 |
| // Minimum Hamming weight: 3 |
| // Maximum Hamming weight: 11 |
| // |
| localparam int FsmStateWidth = 16; |
| typedef enum logic [FsmStateWidth-1:0] { |
| ResetSt = 16'b1111011010111100, |
| IdleSt = 16'b0000011110101101, |
| ClkMuxSt = 16'b1100111011001001, |
| CntIncrSt = 16'b0011001111000111, |
| CntProgSt = 16'b0000110001010100, |
| TransCheckSt = 16'b0110111010110000, |
| TokenHashSt = 16'b1101001000111111, |
| FlashRmaSt = 16'b1110100010001111, |
| TokenCheck0St = 16'b0010000011000000, |
| TokenCheck1St = 16'b1101010101101111, |
| TransProgSt = 16'b1000000110101011, |
| PostTransSt = 16'b0110110100101100, |
| ScrapSt = 16'b1010100001010001, |
| EscalateSt = 16'b1011110110011011, |
| InvalidSt = 16'b0011000101001100 |
| } fsm_state_e; |
| |
| /////////////////////////////////////////// |
| // Manufacturing State Transition Matrix // |
| /////////////////////////////////////////// |
| |
| // Helper macro to assemble the token index matrix below. |
| // From TEST_UNLOCKED(N) |
| // -> SCRAP, RMA |
| // -> PROD, PROD_END, DEV |
| // -> TEST_UNLOCKED(N+1)-7 |
| // -> TEST_LOCKED(N)-6 |
| // -> TEST_UNLOCKED0-(N), RAW |
| `define TEST_UNLOCKED(idx) \ |
| {2{ZeroTokenIdx}}, \ |
| {3{TestExitTokenIdx}}, \ |
| {(7-idx){InvalidTokenIdx, \ |
| ZeroTokenIdx}}, \ |
| {(2*idx+2){InvalidTokenIdx}} |
| |
| // Helper macro to assemble the token index matrix below. |
| // From TEST_LOCKED(N) |
| // -> SCRAP |
| // -> RMA |
| // -> PROD, PROD_END, DEV |
| // -> TEST_UNLOCKED(N+1)-7 |
| // -> TEST_LOCKED(N)-6 |
| // -> TEST_UNLOCKED0-(N), RAW |
| `define TEST_LOCKED(idx) \ |
| ZeroTokenIdx, \ |
| InvalidTokenIdx, \ |
| {3{TestExitTokenIdx}}, \ |
| {(7-idx){TestUnlockTokenIdx, \ |
| InvalidTokenIdx}}, \ |
| {(2*idx+2){InvalidTokenIdx}} |
| |
| // 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 |
| {21{InvalidTokenIdx}}, // -> TEST_LOCKED0-6, TEST_UNLOCKED0-7, DEV, PROD, PROD_END, RMA, SCRAP |
| // RMA |
| ZeroTokenIdx, // -> SCRAP |
| {20{InvalidTokenIdx}}, // -> TEST_LOCKED0-6, TEST_UNLOCKED0-7, DEV, PROD, PROD_END, RMA |
| // PROD_END |
| ZeroTokenIdx, // -> SCRAP |
| {20{InvalidTokenIdx}}, // -> TEST_LOCKED0-6, TEST_UNLOCKED0-7, DEV, PROD, PROD_END, RMA |
| // PROD |
| ZeroTokenIdx, // -> SCRAP |
| RmaTokenIdx, // -> RMA |
| {19{InvalidTokenIdx}}, // -> TEST_LOCKED0-6, TEST_UNLOCKED0-7, DEV, PROD, PROD_END |
| // DEV |
| ZeroTokenIdx, // -> SCRAP |
| RmaTokenIdx, // -> RMA |
| {19{InvalidTokenIdx}}, // -> TEST_LOCKED0-6, TEST_UNLOCKED0-7, DEV, PROD, PROD_END |
| // TEST_UNLOCKED0-7, TEST_LOCKED0-6 |
| `TEST_UNLOCKED(7), |
| `TEST_LOCKED(6), |
| `TEST_UNLOCKED(6), |
| `TEST_LOCKED(5), |
| `TEST_UNLOCKED(5), |
| `TEST_LOCKED(4), |
| `TEST_UNLOCKED(4), |
| `TEST_LOCKED(3), |
| `TEST_UNLOCKED(3), |
| `TEST_LOCKED(2), |
| `TEST_UNLOCKED(2), |
| `TEST_LOCKED(1), |
| `TEST_UNLOCKED(1), |
| `TEST_LOCKED(0), |
| `TEST_UNLOCKED(0), |
| // RAW |
| ZeroTokenIdx, // -> SCRAP |
| {4{InvalidTokenIdx}}, // -> RMA, PROD, PROD_END, DEV |
| {8{RawUnlockTokenIdx, // -> TEST_UNLOCKED0-7 |
| InvalidTokenIdx}} // -> RAW, TEST_LOCKED0-6 |
| }; |
| |
| // These macros are only used locally. |
| `undef TEST_LOCKED |
| `undef TEST_UNLOCKED |
| |
| endpackage : lc_ctrl_pkg |