| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // Life cycle state encoding definition. |
| // |
| // DO NOT EDIT THIS FILE DIRECTLY. |
| // It has been generated with |
| // $ ./util/design/gen-lc-state-enc.py --seed ${lc_st_enc.config['seed']} |
| // |
| package lc_ctrl_state_pkg; |
| <% |
| data_width = lc_st_enc.config['secded']['data_width'] |
| ecc_width = lc_st_enc.config['secded']['ecc_width'] |
| |
| def _to_pascal_case(inp): |
| # Split by underscore. For each word, use str.capitalize if the word is all |
| # one case. For words in mixed case, ensure the first character is |
| # capitalized and leave them be otherwise. |
| words = [] |
| for p in inp.split('_'): |
| if not p: |
| # Ignore leading and trailing underscores |
| continue |
| |
| if p == p.lower() or p == p.upper(): |
| words.append(p.capitalize()) |
| else: |
| words.append(p[0].upper() + p[1:]) |
| |
| return ''.join(words) |
| |
| def _print_state_enum(prefix, name, config): |
| indent = ' ' * 4 |
| |
| # Determine name length for nice alignment; build a new dictionary keyed by |
| # the Pascal-case version of the state names. |
| state_len = 0 |
| entry_len = 3 |
| pstates = {} |
| for state, state_cfg in config[name].items(): |
| pstate = _to_pascal_case(state) |
| state_len = max(state_len, len(pstate)) |
| for entry in state_cfg: |
| entry_len = max(entry_len, len(entry)) |
| |
| # Since _to_pascal_case isn't injective, we should check we didn't get |
| # any collisions. |
| assert pstate not in pstates |
| pstates[pstate] = state_cfg |
| |
| out = [] |
| for i, (pstate, state_cfg) in enumerate(pstates.items()): |
| if i: |
| out.append(',\n') |
| out += [indent, prefix, pstate, |
| ' ' * (state_len - len(pstate)), ' = {'] |
| # Need to iterate in reverse since this is a packed value |
| for j, entry in enumerate(reversed(state_cfg)): |
| if j: |
| out.append(', ') |
| |
| ename = 'ZRO' if entry == '0' else entry |
| out += [' ' * (entry_len - len(ename)), ename] |
| out.append('}') |
| |
| return ''.join(out) |
| %> |
| import prim_util_pkg::vbits; |
| |
| /////////////////////////////// |
| // General size declarations // |
| /////////////////////////////// |
| |
| parameter int LcValueWidth = ${data_width}; |
| |
| parameter int NumLcStateValues = ${lc_st_enc.config['num_lc_state_words']}; |
| parameter int LcStateWidth = NumLcStateValues * LcValueWidth; |
| parameter int NumLcStates = ${len(lc_st_enc.config['lc_state'])}; |
| parameter int DecLcStateWidth = vbits(NumLcStates); |
| // Redundant version used in the CSRs. |
| parameter int DecLcStateNumRep = 32/DecLcStateWidth; |
| parameter int ExtDecLcStateWidth = DecLcStateNumRep*DecLcStateWidth; |
| |
| parameter int NumLcCountValues = ${lc_st_enc.config['num_lc_cnt_words']}; |
| parameter int LcCountWidth = NumLcCountValues * LcValueWidth; |
| parameter int NumLcCountStates = ${len(lc_st_enc.config['lc_cnt'])}; |
| parameter int DecLcCountWidth = vbits(NumLcCountStates); |
| |
| // This state is not stored in OTP, but inferred from the locked |
| // status of the secret partitions. Hence, only the decoded ID state |
| // is declared here for exposure through the CSR interface. |
| parameter int NumLcIdStates = 2; |
| parameter int DecLcIdStateWidth = vbits(NumLcIdStates+1); |
| // Redundant version used in the CSRs. |
| parameter int DecLcIdStateNumRep = 32/DecLcIdStateWidth; |
| parameter int ExtDecLcIdStateWidth = DecLcIdStateNumRep*DecLcIdStateWidth; |
| |
| ///////////////////////////////////////////// |
| // Life cycle manufacturing state encoding // |
| ///////////////////////////////////////////// |
| |
| // These values have been generated such that they are incrementally writeable with respect |
| // to the ECC polynomial specified. The values are used to define the life cycle manufacturing |
| // state and transition counter encoding in lc_ctrl_pkg.sv. |
| // |
| // The values are unique and have the following statistics (considering all ${data_width} |
| // data and ${ecc_width} ECC bits): |
| // |
| // - Minimum Hamming weight: ${lc_st_enc.config['stats']['min_hw']} |
| // - Maximum Hamming weight: ${lc_st_enc.config['stats']['max_hw']} |
| // - Minimum Hamming distance from any other value: ${lc_st_enc.config['stats']['min_hd']} |
| // - Maximum Hamming distance from any other value: ${lc_st_enc.config['stats']['max_hd']} |
| // |
| // Hamming distance histogram: |
| // |
| % for bar in lc_st_enc.config['stats']['bars']: |
| // ${bar} |
| % endfor |
| // |
| // |
| // Note that the ECC bits are not defined in this package as they will be calculated by |
| // the OTP ECC logic at runtime. |
| |
| // SEC_CM: MANUF.STATE.SPARSE |
| // The A/B values are used for the encoded LC state. |
| % for word in lc_st_enc.config['genwords']['lc_state']: |
| parameter logic [${data_width-1}:0] A${loop.index} = ${data_width}'b${word[0][ecc_width:]}; // ECC: ${ecc_width}'b${word[0][0:ecc_width]} |
| parameter logic [${data_width-1}:0] B${loop.index} = ${data_width}'b${word[1][ecc_width:]}; // ECC: ${ecc_width}'b${word[1][0:ecc_width]} |
| |
| % endfor |
| |
| // SEC_CM: TRANSITION.CTR.SPARSE |
| // The C/D values are used for the encoded LC transition counter. |
| % for word in lc_st_enc.config['genwords']['lc_cnt']: |
| parameter logic [${data_width-1}:0] C${loop.index} = ${data_width}'b${word[0][ecc_width:]}; // ECC: ${ecc_width}'b${word[0][0:ecc_width]} |
| parameter logic [${data_width-1}:0] D${loop.index} = ${data_width}'b${word[1][ecc_width:]}; // ECC: ${ecc_width}'b${word[1][0:ecc_width]} |
| |
| % endfor |
| |
| parameter logic [${data_width-1}:0] ZRO = ${data_width}'h0; |
| |
| //////////////////////// |
| // Derived enum types // |
| //////////////////////// |
| |
| // Use lc_state_t and lc_cnt_t in interfaces as very wide enumerations ( > 64 bits ) |
| // are not supported for virtual interfaces by Excelium yet |
| // https://github.com/lowRISC/opentitan/issues/8884 (Cadence issue: cds_46570160) |
| // The enumeration types lc_state_e and lc_cnt_e are still ok in other circumstances |
| |
| typedef logic [LcStateWidth-1:0] lc_state_t; |
| typedef enum lc_state_t { |
| ${_print_state_enum('LcSt', 'lc_state', lc_st_enc.config)} |
| } lc_state_e; |
| |
| typedef logic [LcCountWidth-1:0] lc_cnt_t; |
| typedef enum lc_cnt_t { |
| ${_print_state_enum('LcCnt', 'lc_cnt', lc_st_enc.config)} |
| } lc_cnt_e; |
| |
| // Decoded life cycle state, used to interface with CSRs and TAP. |
| typedef enum logic [DecLcStateWidth-1:0] { |
| % for state in lc_st_enc.config['lc_state'].keys(): |
| DecLcSt${_to_pascal_case(state)} = ${loop.index}, |
| % endfor |
| DecLcStPostTrans = ${len(lc_st_enc.config['lc_state']) + 0}, |
| DecLcStEscalate = ${len(lc_st_enc.config['lc_state']) + 1}, |
| DecLcStInvalid = ${len(lc_st_enc.config['lc_state']) + 2} |
| } dec_lc_state_e; |
| |
| typedef dec_lc_state_e [DecLcStateNumRep-1:0] ext_dec_lc_state_t; |
| |
| typedef enum logic [DecLcIdStateWidth-1:0] { |
| DecLcIdBlank, |
| DecLcIdPersonalized, |
| DecLcIdInvalid |
| } dec_lc_id_state_e; |
| |
| typedef logic [DecLcCountWidth-1:0] dec_lc_cnt_t; |
| |
| |
| /////////////////////////////////////////// |
| // Hashed RAW unlock and all-zero tokens // |
| /////////////////////////////////////////// |
| |
| parameter int LcTokenWidth = ${lc_st_enc.config['token_size']}; |
| typedef logic [LcTokenWidth-1:0] lc_token_t; |
| <% token_size = lc_st_enc.config['token_size'] %> |
| % for token in lc_st_enc.config['tokens']: |
| parameter lc_token_t ${token['name']} = { |
| ${"{0:}'h{1:0X}".format(token_size, token['value'])} |
| }; |
| % endfor |
| |
| endpackage : lc_ctrl_state_pkg |