Skip to content

Commit

Permalink
[otbn,dv] Correct the timing for when we zero insn_cnt in model
Browse files Browse the repository at this point in the history
There are two paths by which this can happen in the RTL (the
insn_cnt_clear_int_o signal from otbn_start_stop_control and the way
that otbn_controller can go into a locked state). These have slightly
different timings!

Make sure to model them correctly.

Signed-off-by: Rupert Swarbrick <[email protected]>
  • Loading branch information
rswarbrick committed Aug 16, 2024
1 parent b5b4087 commit 7633463
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 11 deletions.
31 changes: 21 additions & 10 deletions hw/ip/otbn/dv/otbnsim/sim/sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,12 @@ def _on_retire(self,

return changes

def _delayed_insn_cnt_zero(self) -> None:
def _delayed_insn_cnt_zero(self, delay_if_locking: int) -> None:
'''Zero INSN_CNT if we are in a wiping state and are going to lock
after wipe.
This is delayed by a cycle (using the zero_insn_cnt_next flag) to match
the timing in the RTL.
This is delayed by delay_if_locking (using state.time_to_insn_cnt_zero)
to match the timing in the RTL.
'''
assert self.state.get_fsm_state() in [FsmState.PRE_WIPE,
FsmState.WIPING]
Expand All @@ -156,12 +156,23 @@ def _delayed_insn_cnt_zero(self) -> None:
if self.state.ext_regs.read('INSN_CNT', True) == 0:
return

if self.state.zero_insn_cnt_next or not self.state.lock_immediately:
# In this case, we know we want to zero INSN_CNT. There might be an
# operation to do so that has already been enqueued. If not (or if it
# would be waiting longer than delay_if_locking), switch to a new
# counter.
if self.state.time_to_insn_cnt_zero is None:
self.state.time_to_insn_cnt_zero = delay_if_locking
count = min(self.state.time_to_insn_cnt_zero, delay_if_locking)

if count == 0:
# If _time_to_insn_cnt_zero is now zero, it means that this is the
# cycle to update insn_cnt.
self.state.ext_regs.write('INSN_CNT', 0, True)
self.state.zero_insn_cnt_next = False
if self.state.lock_immediately:
# Zero INSN_CNT in the *next* cycle to match RTL control flow.
self.state.zero_insn_cnt_next = True
self.state.time_to_insn_cnt_zero = None
else:
# If _time_to_insn_cnt_zero isn't zero, we should decrement it
# (maybe we'll update insn_cnt next cycle).
self.state.time_to_insn_cnt_zero = count - 1

def step(self, verbose: bool) -> StepRes:
'''Run a single cycle.
Expand Down Expand Up @@ -378,7 +389,7 @@ def _step_pre_wipe(self, verbose: bool) -> StepRes:
self.state.ext_regs.write('WIPE_START', 0, True)

# Zero INSN_CNT once if we're going to lock after wipe.
self._delayed_insn_cnt_zero()
self._delayed_insn_cnt_zero(0)

if self.state.wsrs.URND.running:
# Reflect wiping in STATUS register if it has not been updated yet.
Expand Down Expand Up @@ -418,7 +429,7 @@ def _step_wiping(self, verbose: bool) -> StepRes:
self.state.lock_after_wipe = True

# Zero INSN_CNT once if we're going to lock after wipe.
self._delayed_insn_cnt_zero()
self._delayed_insn_cnt_zero(1)

if self.state.wipe_cycles == 1:
# This is the penultimate clock cycle of a wipe round. We want to
Expand Down
7 changes: 6 additions & 1 deletion hw/ip/otbn/dv/otbnsim/sim/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,12 @@ def __init__(self) -> None:
# cancelled).
self.injected_err_bits = 0
self.lock_immediately = False
self.zero_insn_cnt_next = False

# OTBN might zero its insn_cnt register during a secure wipe. The
# precise cycle that this happens depends slightly on how we decide to
# do so. If this is not None, it is a counter of the number of cycles
# before the zeroing should happen.
self.time_to_insn_cnt_zero = None # type: Optional[int]

# If this is set, all software errors should result in the model status
# being locked.
Expand Down

0 comments on commit 7633463

Please sign in to comment.