Skip to content

Commit

Permalink
[lc_ctrl] Always allow transitions into scrap
Browse files Browse the repository at this point in the history
We should always allow transitions into scrap, no matter whether the
transition counter is maxed out or not.

In order to prevent any abuse of this unconditional transition path,
we max out the counter and program the LC state to SCRAP already in the
transition counter increment phase instead of programming the counter
state and LC state separately in two phases as all other transitions.

This fixes #13617.

Signed-off-by: Michael Schaffner <[email protected]>
  • Loading branch information
msfschaffner committed Feb 6, 2024
1 parent f10124c commit a955ec3
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 7 deletions.
5 changes: 4 additions & 1 deletion hw/ip/lc_ctrl/dv/env/lc_ctrl_scoreboard.sv
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,10 @@ class lc_ctrl_scoreboard extends cip_base_scoreboard #(
end

// Transition to SCRAP state always programs LcCnt24
if (LcTargetState == LcStScrap) lc_cnt_exp = LcCnt24;
if (LcTargetState == LcStScrap) begin
lc_cnt_exp = LcCnt24;
lc_state_exp = LcStScrap;
end

`uvm_info(`gfn, $sformatf(
"predict_otp_prog_req: state=%s count=%s", lc_state_exp.name(), lc_cnt_exp.name),
Expand Down
32 changes: 28 additions & 4 deletions hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_errors_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,13 @@ class lc_ctrl_errors_vseq extends lc_ctrl_smoke_vseq;
// SW transition request
// verilog_format: off - avoid bad formatting
if ((err_inj.state_err || valid_state_for_trans(lc_state)) &&
(err_inj.count_err || err_inj.transition_count_err ||
(lc_cnt != LcCnt24 && lc_state != LcStScrap))) begin
(err_inj.count_err ||
// We can't inject a transition count error if we're in RMA or PROD_END since the only
// valid transition from those states is into SCRAP, which is always allowed (even when
// the transition counter is maxed out).
(err_inj.transition_count_err && !(lc_state inside {DecLcStRma, DecLcStProdEnd})) ||
(lc_cnt != LcCnt24 && lc_state != LcStScrap) ||
(lc_cnt == LcCnt24 && lc_state == LcStScrap))) begin
lc_ctrl_state_pkg::lc_token_t token_val = get_random_token();
randomize_next_lc_state(dec_lc_state(lc_state));
`uvm_info(`gfn, $sformatf(
Expand Down Expand Up @@ -485,10 +490,21 @@ class lc_ctrl_errors_vseq extends lc_ctrl_smoke_vseq;
if (!err_inj.transition_err && !err_inj.state_err) {
// Valid transition
next_lc_state inside {VALID_NEXT_STATES[curr_lc_state]};
// The constraints cannot be solved for if the only valid transition is into SCRAP, hence
// we specifically allow those cases and make sure we're not using RMA and PROD_END to
// test transition counter errors.
if (err_inj.transition_count_err &&
!(curr_lc_state inside {DecLcStRma, DecLcStProdEnd})) {
// Transition count errors due to counter saturation are injected by requesting a
// transition into any state with a saturated counter in OTP. This does not work if the
// target state is SCRAP, though, since a transition into SCRAP is always allowed.
next_lc_state != DecLcStScrap;
}
} else if (!err_inj.state_err) {
// Invalid transition
!(next_lc_state inside {VALID_NEXT_STATES[curr_lc_state]});
})
}
)
`uvm_info(`gfn,$sformatf("randomize_next_lc_state: next_lc_state=%s",
next_lc_state.name()), UVM_MEDIUM)
endfunction
Expand Down Expand Up @@ -570,7 +586,15 @@ class lc_ctrl_errors_vseq extends lc_ctrl_smoke_vseq;
if (!err_inj.state_err && !err_inj.state_illegal_err) begin
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(lc_state,
// lc_state should be valid for transition
lc_state inside {LcValidStateForTrans};)
lc_state inside {LcValidStateForTrans};
// The only valid transitions from PROD_END and RMA are
// into SCRAP. Since transitioning into SCRAP is always
// allowed, we cannot use these states as base states to
// test the transition counter saturation error.
if (err_inj.transition_count_err) {
!(lc_state inside {DecLcStProdEnd, DecLcStRma});
}
)
`uvm_info(`gfn, $sformatf("drive_otp_i: driving lc_state=%s", lc_state.name), UVM_MEDIUM)
end else begin
// Force invalid state on input optionally with illegal coding
Expand Down
3 changes: 2 additions & 1 deletion hw/ip/lc_ctrl/dv/env/seq_lib/lc_ctrl_smoke_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class lc_ctrl_smoke_vseq extends lc_ctrl_base_vseq;
cfg.set_test_phase(LcCtrlDutReady);

// SW transition request
if (valid_state_for_trans(lc_state) && lc_cnt != LcCnt24) begin
if (valid_state_for_trans(lc_state) && (lc_cnt != LcCnt24 ||
lc_cnt == LcCnt24 && lc_state == LcStScrap)) begin
lc_ctrl_state_pkg::lc_token_t token_val = get_random_token();
randomize_next_lc_state(dec_lc_state(lc_state));
`uvm_info(`gfn, $sformatf(
Expand Down
8 changes: 7 additions & 1 deletion hw/ip/lc_ctrl/rtl/lc_ctrl_state_transition.sv
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,15 @@ module lc_ctrl_state_transition
default: trans_cnt_oflw_error_o = 1'b1;
endcase // lc_cnt_i

// In case the transition target is SCRAP, max out the counter.
// We always allow transitions into the SCRAP state, so the overflow error is silenced in that
// particular case. In that case we max out the transition counter and force the
// next_lc_state already into SCRAP so that the error silencing above cannot be abused. This
// means that when moving to SCRAP state, we program LcStScrap twice: once during the counter
// increment phase, and once during the actual state programming phase.
if (trans_target_i == {DecLcStateNumRep{DecLcStScrap}}) begin
next_lc_cnt_o = LcCnt24;
next_lc_state_o = LcStScrap;
trans_cnt_oflw_error_o = 1'b0;
end
end

Expand Down

0 comments on commit a955ec3

Please sign in to comment.