blob: 681c4f0cf7962ea22903dbf987688cda36ab132b [file] [log] [blame]
// 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