From b937c90a9c8d39a13452a36c126e238d1cfcf7a4 Mon Sep 17 00:00:00 2001 From: Guillermo Maturana Date: Tue, 29 Aug 2023 17:25:34 +0000 Subject: [PATCH] [dv/otp_ctrl] Update templates to support parts without digest Signed-off-by: Guillermo Maturana --- hw/ip/otp_ctrl/data/otp_ctrl_env_pkg.sv.tpl | 4 + .../otp_ctrl/data/otp_ctrl_scoreboard.sv.tpl | 32 ++++---- hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv | 76 ++++++++++++------- 3 files changed, 68 insertions(+), 44 deletions(-) diff --git a/hw/ip/otp_ctrl/data/otp_ctrl_env_pkg.sv.tpl b/hw/ip/otp_ctrl/data/otp_ctrl_env_pkg.sv.tpl index 265fa2991d0c2..8c0a75b53d04f 100644 --- a/hw/ip/otp_ctrl/data/otp_ctrl_env_pkg.sv.tpl +++ b/hw/ip/otp_ctrl/data/otp_ctrl_env_pkg.sv.tpl @@ -93,7 +93,11 @@ package otp_ctrl_env_pkg; part_name = Name.from_snake_case(part["name"]) part_name_camel = part_name.as_camel_case() %>\ +% if part["sw_digest"] or part["hw_digest"]: ${part_name_camel}DigestOffset >> 2${"" if loop.last else ","} +% else: + -1${"" if loop.last else ","} // This partition does not have a digest. +% endif % endfor }; diff --git a/hw/ip/otp_ctrl/data/otp_ctrl_scoreboard.sv.tpl b/hw/ip/otp_ctrl/data/otp_ctrl_scoreboard.sv.tpl index 6d5d73f633881..cf7a336bddb2d 100644 --- a/hw/ip/otp_ctrl/data/otp_ctrl_scoreboard.sv.tpl +++ b/hw/ip/otp_ctrl/data/otp_ctrl_scoreboard.sv.tpl @@ -141,7 +141,7 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) otp_ctrl_pkg::otp_lc_data_t exp_lc_data; bit [otp_ctrl_pkg::KeyMgrKeyWidth-1:0] exp_keymgr_key0, exp_keymgr_key1; - if (dai_digest_ip != LifeCycleIdx) begin + if (PartInfo[dai_digest_ip].sw_digest || PartInfo[dai_digest_ip].hw_digest) begin bit [TL_DW-1:0] otp_addr = PART_OTP_DIGEST_ADDRS[dai_digest_ip]; otp_a[otp_addr] = cfg.mem_bkdr_util_h.read32(otp_addr << 2); otp_a[otp_addr+1] = cfg.mem_bkdr_util_h.read32((otp_addr << 2) + 4); @@ -733,7 +733,7 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) // However, digest is always readable except SW partitions (Issue #5752). (is_secret(dai_addr) && get_digest_reg_val(part_idx) != 0 && !is_digest(dai_addr)) || - // If the partition is has key material and lc_creator_seed_sw_rw is disable, then + // If the partition has key material and lc_creator_seed_sw_rw is disable, then // return access error. (PartInfo[part_idx].iskeymgr && !is_digest(dai_addr) && cfg.otp_ctrl_vif.lc_creator_seed_sw_rw_en_i != lc_ctrl_pkg::On)) begin @@ -785,9 +785,15 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) end DaiWrite: begin bit[TL_AW-1:0] otp_addr = get_scb_otp_addr(); + bit is_write_locked; // check if write locked - if (get_digest_reg_val(part_idx) != 0 || - (PartInfo[part_idx].iskeymgr && !is_digest(dai_addr) && + if (PartInfo[part_idx].hw_digest || PartInfo[part_idx].sw_digest) begin + is_write_locked = get_digest_reg_val(part_idx) != 0; + end else begin + is_write_locked = 0; + end + + if (is_write_locked || (PartInfo[part_idx].iskeymgr && !is_digest(dai_addr) && cfg.otp_ctrl_vif.lc_creator_seed_sw_rw_en_i != lc_ctrl_pkg::On)) begin predict_err(OtpDaiErrIdx, OtpAccessError); end else begin @@ -1101,17 +1107,10 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) virtual function void predict_digest_csrs(); % for part in write_locked_digest_parts: <% part_name = Name.from_snake_case(part["name"]) %>\ - % if len(part["name"]) < 8: - void'(ral.${part_name.as_snake_case()}_digest[0].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[${part_name.as_camel_case()}Idx]]), - .kind(UVM_PREDICT_DIRECT))); - void'(ral.${part_name.as_snake_case()}_digest[1].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[${part_name.as_camel_case()}Idx] + 1]), - .kind(UVM_PREDICT_DIRECT))); - % else: void'(ral.${part_name.as_snake_case()}_digest[0].predict( .value(otp_a[PART_OTP_DIGEST_ADDRS[${part_name.as_camel_case()}Idx]]), .kind(UVM_PREDICT_DIRECT))); void'(ral.${part_name.as_snake_case()}_digest[1].predict( .value(otp_a[PART_OTP_DIGEST_ADDRS[${part_name.as_camel_case()}Idx] + 1]), .kind(UVM_PREDICT_DIRECT))); - %endif % if not loop.last: %endif @@ -1301,13 +1300,9 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) part_name = Name.from_snake_case(part["name"]) part_name_snake = part_name.as_snake_case() %>\ - % if len(part["name"]) < 13: - ${part_name.as_camel_case()}Idx: digest = {`gmv(ral.${part_name_snake}_digest[1]), `gmv(ral.${part_name_snake}_digest[0])}; - % else: ${part_name.as_camel_case()}Idx: begin digest = {`gmv(ral.${part_name_snake}_digest[1]), `gmv(ral.${part_name_snake}_digest[0])}; end - % endif % endfor default: `uvm_fatal(`gfn, $sformatf("Partition %0d does not have digest", part_idx)) endcase @@ -1349,8 +1344,15 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) predict_err(Otp${part_name_camel}ErrIdx, OtpAccessError); custom_err = 1; if (cfg.en_cov) begin + % if part["write_lock"] == "Digest": cov.unbuf_access_lock_cg_wrap[${part_name_camel}Idx].sample(.read_lock(1), .write_lock(get_digest_reg_val(${part_name_camel}Idx) != 0), .is_write(0)); + % else: + // TODO: we should probably create a different covergroup + // for unbuffered partitions without digest. + cov.unbuf_access_lock_cg_wrap[${part_name_camel}Idx].sample(.read_lock(1), + .write_lock(0), .is_write(0)); + % endif end return 0; end diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv index 4a194522a2c6d..d4fd7aa43844e 100644 --- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv +++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv @@ -141,7 +141,7 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) otp_ctrl_pkg::otp_lc_data_t exp_lc_data; bit [otp_ctrl_pkg::KeyMgrKeyWidth-1:0] exp_keymgr_key0, exp_keymgr_key1; - if (dai_digest_ip != LifeCycleIdx) begin + if (PartInfo[dai_digest_ip].sw_digest || PartInfo[dai_digest_ip].hw_digest) begin bit [TL_DW-1:0] otp_addr = PART_OTP_DIGEST_ADDRS[dai_digest_ip]; otp_a[otp_addr] = cfg.mem_bkdr_util_h.read32(otp_addr << 2); otp_a[otp_addr+1] = cfg.mem_bkdr_util_h.read32((otp_addr << 2) + 4); @@ -723,7 +723,7 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) // However, digest is always readable except SW partitions (Issue #5752). (is_secret(dai_addr) && get_digest_reg_val(part_idx) != 0 && !is_digest(dai_addr)) || - // If the partition is has key material and lc_creator_seed_sw_rw is disable, then + // If the partition has key material and lc_creator_seed_sw_rw is disable, then // return access error. (PartInfo[part_idx].iskeymgr && !is_digest(dai_addr) && cfg.otp_ctrl_vif.lc_creator_seed_sw_rw_en_i != lc_ctrl_pkg::On)) begin @@ -775,9 +775,15 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) end DaiWrite: begin bit[TL_AW-1:0] otp_addr = get_scb_otp_addr(); + bit is_write_locked; // check if write locked - if (get_digest_reg_val(part_idx) != 0 || - (PartInfo[part_idx].iskeymgr && !is_digest(dai_addr) && + if (PartInfo[part_idx].hw_digest || PartInfo[part_idx].sw_digest) begin + is_write_locked = get_digest_reg_val(part_idx) != 0; + end else begin + is_write_locked = 0; + end + + if (is_write_locked || (PartInfo[part_idx].iskeymgr && !is_digest(dai_addr) && cfg.otp_ctrl_vif.lc_creator_seed_sw_rw_en_i != lc_ctrl_pkg::On)) begin predict_err(OtpDaiErrIdx, OtpAccessError); end else begin @@ -1114,25 +1120,25 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) void'(ral.owner_sw_cfg_digest[1].predict( .value(otp_a[PART_OTP_DIGEST_ADDRS[OwnerSwCfgIdx] + 1]), .kind(UVM_PREDICT_DIRECT))); - void'(ral.hw_cfg0_digest[0].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[HwCfg0Idx]]), - .kind(UVM_PREDICT_DIRECT))); - void'(ral.hw_cfg0_digest[1].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[HwCfg0Idx] + 1]), - .kind(UVM_PREDICT_DIRECT))); - - void'(ral.secret0_digest[0].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[Secret0Idx]]), - .kind(UVM_PREDICT_DIRECT))); - void'(ral.secret0_digest[1].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[Secret0Idx] + 1]), - .kind(UVM_PREDICT_DIRECT))); - - void'(ral.secret1_digest[0].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[Secret1Idx]]), - .kind(UVM_PREDICT_DIRECT))); - void'(ral.secret1_digest[1].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[Secret1Idx] + 1]), - .kind(UVM_PREDICT_DIRECT))); - - void'(ral.secret2_digest[0].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[Secret2Idx]]), - .kind(UVM_PREDICT_DIRECT))); - void'(ral.secret2_digest[1].predict(.value(otp_a[PART_OTP_DIGEST_ADDRS[Secret2Idx] + 1]), - .kind(UVM_PREDICT_DIRECT))); + void'(ral.hw_cfg0_digest[0].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[HwCfg0Idx]]), .kind(UVM_PREDICT_DIRECT))); + void'(ral.hw_cfg0_digest[1].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[HwCfg0Idx] + 1]), .kind(UVM_PREDICT_DIRECT))); + + void'(ral.secret0_digest[0].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[Secret0Idx]]), .kind(UVM_PREDICT_DIRECT))); + void'(ral.secret0_digest[1].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[Secret0Idx] + 1]), .kind(UVM_PREDICT_DIRECT))); + + void'(ral.secret1_digest[0].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[Secret1Idx]]), .kind(UVM_PREDICT_DIRECT))); + void'(ral.secret1_digest[1].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[Secret1Idx] + 1]), .kind(UVM_PREDICT_DIRECT))); + + void'(ral.secret2_digest[0].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[Secret2Idx]]), .kind(UVM_PREDICT_DIRECT))); + void'(ral.secret2_digest[1].predict( + .value(otp_a[PART_OTP_DIGEST_ADDRS[Secret2Idx] + 1]), .kind(UVM_PREDICT_DIRECT))); endfunction function void update_digest_to_otp(int part_idx, bit [TL_DW*2-1:0] digest); @@ -1310,15 +1316,27 @@ class otp_ctrl_scoreboard #(type CFG_T = otp_ctrl_env_cfg) virtual function bit [TL_DW*2-1:0] get_digest_reg_val(int part_idx); bit [TL_DW*2-1:0] digest; case (part_idx) - VendorTestIdx: digest = {`gmv(ral.vendor_test_digest[1]), `gmv(ral.vendor_test_digest[0])}; + VendorTestIdx: begin + digest = {`gmv(ral.vendor_test_digest[1]), `gmv(ral.vendor_test_digest[0])}; + end CreatorSwCfgIdx: begin digest = {`gmv(ral.creator_sw_cfg_digest[1]), `gmv(ral.creator_sw_cfg_digest[0])}; end - OwnerSwCfgIdx: digest = {`gmv(ral.owner_sw_cfg_digest[1]), `gmv(ral.owner_sw_cfg_digest[0])}; - HwCfg0Idx: digest = {`gmv(ral.hw_cfg0_digest[1]), `gmv(ral.hw_cfg0_digest[0])}; - Secret0Idx: digest = {`gmv(ral.secret0_digest[1]), `gmv(ral.secret0_digest[0])}; - Secret1Idx: digest = {`gmv(ral.secret1_digest[1]), `gmv(ral.secret1_digest[0])}; - Secret2Idx: digest = {`gmv(ral.secret2_digest[1]), `gmv(ral.secret2_digest[0])}; + OwnerSwCfgIdx: begin + digest = {`gmv(ral.owner_sw_cfg_digest[1]), `gmv(ral.owner_sw_cfg_digest[0])}; + end + HwCfg0Idx: begin + digest = {`gmv(ral.hw_cfg0_digest[1]), `gmv(ral.hw_cfg0_digest[0])}; + end + Secret0Idx: begin + digest = {`gmv(ral.secret0_digest[1]), `gmv(ral.secret0_digest[0])}; + end + Secret1Idx: begin + digest = {`gmv(ral.secret1_digest[1]), `gmv(ral.secret1_digest[0])}; + end + Secret2Idx: begin + digest = {`gmv(ral.secret2_digest[1]), `gmv(ral.secret2_digest[0])}; + end default: `uvm_fatal(`gfn, $sformatf("Partition %0d does not have digest", part_idx)) endcase return digest;