[otbn] Operational states and commands
Specify the operational states OTBN can be in.
- Consolidate all user (host-software) initiated actions into the CMD
register. To keep things simple, I resorted to allowing only a single
command being executed at any time, and in consequence encoding the
command as number, not as bitfield. This also means that performing a
secure wipe of IMEM and DMEM now requires two host-initiated actions.
(Nobody ever asked explicitly for them being a single operation.)
The CMD register is 8 bit wide to make multi-bit encodings and
extensions of the commands easier going forward.
- Expand the STATUS register to show what's currently going on within
OTBN: mirror all CMDs in the status register.
The STATUS register is 8 bit wide to make it easier to extend going
forward. We already plan to have a LOCKED status.
Update all users of the registers:
- Update all software to make use of the new CMD and STATUS registers.
- Update otbnsim to make use of the new registers. Refactor the err_bits
module to hold other constants as well.
- Update DV to make use of the new registers.
Fixes #7434
Signed-off-by: Philipp Wagner <phw@lowrisc.org>
diff --git a/hw/ip/otbn/data/otbn.hjson b/hw/ip/otbn/data/otbn.hjson
index 234ce52..0a02f45 100644
--- a/hw/ip/otbn/data/otbn.hjson
+++ b/hw/ip/otbn/data/otbn.hjson
@@ -134,23 +134,64 @@
registers: [
{ name: "CMD"
desc: "command register",
- swaccess: "r0w1c",
+ swaccess: "wo",
hwaccess: "hro",
hwext: "true",
hwqe: "true",
fields: [
- { bits: "0"
- name: "start"
+ { bits: "7:0"
+ name: "cmd"
+ resval: 0,
desc: '''
- Start the operation
+ Initiates an OTBN operation.
- The completion is signalled by the done interrupt.
+ A command starts an OTBN operation. While performing the operation,
+ OTBN is busy; the !!STATUS register reflects that.
+
+ All operations signal their completion by raising the done
+ interrupt; alternatively, software may poll the !!STATUS register.
+
+ New commands are only accepted while OTBN is idle, as indicated
+ by the !!STATUS register. Writes while !!STATUS is not IDLE are
+ ignored.
+
+ Unrecognized commands are ignored.
+
+ <table>
+ <thead>
+ <tr>
+ <th>Value</th>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>0x01</td>
+ <td>EXECUTE</td>
+ <td>
+ Start the execution of the program stored in the
+ instruction memory, starting at address !!START_ADDR.
+ </td>
+ </tr>
+ <tr>
+ <td>0x02</td>
+ <td>SEC_WIPE_DMEM</td>
+ <td>Securely remove all contents from the data memory.</td>
+ </tr>
+ <tr>
+ <td>0x03</td>
+ <td>SEC_WIPE_IMEM</td>
+ <td>
+ Securely remove all contents from the instruction memory.
+ </td>
+ </tr>
+ </tbody>
+ </table>
'''
tags: [
- // Don't write this field in the automated CSR tests. Doing so will
- // start OTBN, but we won't have initialised its memory with any
- // code, so we'll get Xs on its interfaces and everything will be
- // a bit of a mess!
+ // Don't write this field in the automated CSR tests; the commands
+ // are tested in more controlled form.
"excl:CsrAllTests:CsrExclWrite"
]
}
@@ -162,9 +203,49 @@
hwaccess: "hwo",
hwext: "true",
fields: [
- { bits: "0",
- name: "busy",
- desc: "OTBN is performing an operation."
+ { bits: "7:0",
+ name: "status",
+ resval: 0,
+ // Note: Keep the list of status codes in sync with status_e in
+ // otbn_pkg.sv.
+ desc: '''
+ Indicates the current state OTBN is in.
+
+ All BUSY flags represent an operation started by a write to the
+ !!CMD register.
+
+ <table>
+ <thead>
+ <tr>
+ <th>Value</th>
+ <th>Name</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>0x00</td>
+ <td>IDLE</td>
+ <td>OTBN is not performing any action.</td>
+ </tr>
+ <tr>
+ <td>0x01</td>
+ <td>BUSY_EXECUTE</td>
+ <td>OTBN is executing software.</td>
+ </tr>
+ <tr>
+ <td>0x02</td>
+ <td>BUSY_SEC_WIPE_DMEM</td>
+ <td>OTBN is securely wiping the data memory.</td>
+ </tr>
+ <tr>
+ <td>0x03</td>
+ <td>BUSY_SEC_WIPE_IMEM</td>
+ <td>OTBN is securely wiping the instruction memory.</td>
+ </tr>
+ </tbody>
+ </table>
+ '''
}
]
} // register : status
@@ -267,7 +348,7 @@
resval: 0,
desc: '''
Byte address in the instruction memory OTBN starts to execute from
- when instructed to do so with the !!CMD.start .
+ when instructed to do so by issuing the EXECUTE command.
'''
}
]
@@ -321,28 +402,6 @@
}
]
} // register : fatal_alert_cause
- { name: "SEC_WIPE",
- desc: '''
- Trigger a secure wipe operation.
-
- This register should only be accesed while OTBN is not busy, as indicated by the !!STATUS.busy flag.
- Access attempts while OTBN is busy are ignored.
- '''
- swaccess: "wo",
- hwaccess: "hro",
- fields: [
- { bits: "0",
- name: "dmem",
- resval: 0,
- desc: "Write 1 to securely wipe data memory."
- }
- { bits: "1",
- name: "imem",
- resval: 0,
- desc: "Write 1 to securely wipe instruction memory."
- }
- ]
- } // register : sec_wipe
{ name: "INSN_CNT",
desc: "Instruction Counter",
hwext: "true",
@@ -375,7 +434,7 @@
desc: '''
Instruction Memory.
- This register should only be accesed while OTBN is not busy, as indicated by the !!STATUS.busy flag.
+ The instruction memory may only be accessed through this register while OTBN is idle, as indicated by the !!STATUS register.
Accesses while OTBN is not idle result in a fatal error, setting the fatal_illegal_bus_access error bit.
'''
}
@@ -393,7 +452,7 @@
desc: '''
Data Memory.
- This register should only be accesed while OTBN is not busy, as indicated by the !!STATUS.busy flag.
+ The data memory may only be accessed through this register while OTBN is idle, as indicated by the !!STATUS register.
Accesses while OTBN is not idle result in a fatal error, setting the fatal_illegal_bus_access error bit.
'''
}
diff --git a/hw/ip/otbn/doc/_index.md b/hw/ip/otbn/doc/_index.md
index 82c1641..f9aa1e2 100644
--- a/hw/ip/otbn/doc/_index.md
+++ b/hw/ip/otbn/doc/_index.md
@@ -440,8 +440,8 @@
A secure wipe is performed automatically in certain situations, or can be requested manually by the host software.
The full secure wipe is automatically initiated as a local reaction to a fatal error.
-A secure wipe of only the internal state is performed whenever an OTBN operation is completed and after a recoverable error.
-Finally, host software can manually trigger the data memory and instruction memory secure wipe operations by writing to the {{< regref "SEC_WIPE">}} register.
+A secure wipe of only the internal state is performed whenever an OTBN operation is complete and after a recoverable error.
+Finally, host software can manually trigger the data memory and instruction memory secure wipe operations by issuing an appropriate [command](#design-details-commands).
Refer to the [Secure Wipe]({{<relref "#design-details-secure-wipe">}}) section for implementation details.
@@ -497,7 +497,7 @@
Both memories can be accessed through OTBN's register interface ({{< regref "DMEM" >}} and {{< regref "IMEM" >}}).
These accesses are ignored if OTBN is busy.
-A host processor can check whether OTBN is busy by reading the {{< regref "STATUS.busy">}} flag.
+A host processor can check whether OTBN is busy by reading the {{< regref "STATUS">}} register.
All memory accesses through the register interface must be word-aligned 32b word accesses.
### Random Numbers
@@ -519,6 +519,47 @@
Each new execution of OTBN will reseed the `URND` LFSR.
The LFSR state is advanced every cycle when OTBN is running.
+### Operational States {#design-details-operational-states}
+
+OTBN can be in different operational states.
+OTBN is *busy* for as long it is performing an operation.
+Otherwise OTBN is *idle*.
+
+The current operational state is reflected in the {{< regref "STATUS" >}} register.
+- If OTBN is idle, the {{< regref "STATUS" >}} register is set to `IDLE`.
+- If OTBN is busy, the {{< regref "STATUS" >}} register is set to one of the values starting with `BUSY_`.
+
+OTBN transitions into the busy state as result of host software [issuing a command](#design-details-commands); OTBN is then said to perform an operation.
+OTBN transitions out of the busy state whenever the operation has completed.
+In the {{< regref "STATUS" >}} register the different `BUSY_*` values represent the operation that is currently being performed.
+
+A transition from busy to idle is signaled by the `done` interrupt ({{< regref "INTR_STATE.done" >}}).
+
+### Operations and Commands {#design-details-commands}
+
+OTBN understands a set of commands to perform certain operations.
+Commands are issued by writing to the {{< regref "CMD" >}} register.
+
+The `EXECUTE` command starts the [execution of the application](#design-details-software-execution) contained in OTBN's instruction memory.
+
+The `SEC_WIPE_DMEM` command [securely wipes the data memory](#design-details-secure-wipe).
+
+The `SEC_WIPE_IMEM` command [securely wipes the instruction memory](#design-details-secure-wipe).
+
+### Software Execution {#design-details-software-execution}
+
+Software execution on OTBN is triggered by host software by [issuing the `EXECUTE` command](#design-details-commands).
+The software then runs to completion, without the ability for host software to interrupt or inspect the execution.
+
+- OTBN transitions into the busy state, and reflects this by setting {{< regref "STATUS">}} to `BUSY_EXECUTE`.
+- The internal randomness source, which provides random numbers to the `URND` CSR and WSR, is re-seeded from the EDN.
+- The instruction at {{< regref "START_ADDR" >}} is fetched and executed.
+- From this point on, all subsequent instructions are executed according to their semantics until either an {{< otbnInsnRef "ECALL" >}} instruction is executed, or an error is detected.
+- A [secure wipe of internal state](#design-details-secure-wipe-internal) is performed.
+- The {{< regref "ERR_BITS" >}} register is set to indicate either a successful execution (value `0`), or to indicate the error that was observed (a non-zero value).
+- OTBN transitions into the [idle state](#design-details-operational-states).
+ This transition is signaled by raising the `done` interrupt ({{< regref "INTR_STATE.done" >}}), and reflected in the {{< regref "STATUS" >}} register.
+
### Error Handling and Reporting {#design-details-error-handling-and-reporting}
OTBN is able to detect a range of errors.
@@ -543,7 +584,8 @@
- No more instructions are fetched or executed.
- A [secure wipe of internal state](#design-details-secure-wipe-internal) is performed.
- The {{< regref "ERR_BITS" >}} register is set to a non-zero value that describes the error.
- - The current operation is marked as complete by setting {{< regref "INTR_STATE.done" >}} and clearing {{< regref "STATUS.busy" >}}.
+ - The current operation is marked as complete by setting {{< regref "INTR_STATE.done" >}}.
+ - The {{< regref "STATUS" >}} register is set to `IDLE`.
2. A [recoverable alert]({{< relref "#alerts" >}}) is raised.
The host software can start another operation on OTBN after a recoverable error was detected.
@@ -556,11 +598,11 @@
The following actions are taken when OTBN detects a fatal error:
1. A [secure wipe of the data memory](#design-details-secure-wipe-dmem) and a [secure wipe of the instruction memory](#design-details-secure-wipe-imem) is initiated.
-2. If OTBN is busy, as indicated by {{< regref "STATUS.busy" >}}, then the currently running operation is terminated, similarly to how an operation ends after an {{< otbnInsnRef "ECALL" >}} instruction [is executed](#writing-otbn-applications-ecall):
+2. If OTBN [is not idle](#design-details-operational-states), then the currently running operation is terminated, similarly to how an operation ends after an {{< otbnInsnRef "ECALL" >}} instruction [is executed](#writing-otbn-applications-ecall):
- No more instructions are fetched or executed.
- A [secure wipe of internal state](#design-details-secure-wipe-internal) is performed.
- The {{< regref "ERR_BITS" >}} register is set to a non-zero value that describes the error.
- - The current operation is marked as completed by setting {{< regref "INTR_STATE.done" >}} and clearing {{< regref "STATUS.busy" >}}.
+ - The current operation is marked as complete by setting {{< regref "INTR_STATE.done" >}}.
3. A [fatal alert]({{< relref "#alerts" >}}) is raised.
Note that OTBN can detect some errors even when it isn't running.
@@ -584,7 +626,7 @@
If OTBN was running, this value will also be reflected in the {{< regref "ERR_BITS" >}} register.
A fatal alert can only be cleared by resetting OTBN through the `rst_ni` line.
-### Reaction to Life Cycle Escalation Requests
+### Reaction to Life Cycle Escalation Requests {#design-details-lifecycle-escalation}
OTBN receives and reacts to escalation signals from the [life cycle controller]({{< relref "/hw/ip/lc_ctrl/doc#security-escalation" >}}).
An incoming life cycle escalation is a fatal error of type `lifecycle_escalation` and treated as described in the section [Fatal Errors](#design-details-fatal-errors).
@@ -593,9 +635,7 @@
OTBN exposes a single-bit `idle_o` signal, intended to be used by the clock manager to clock-gate the block when it is not in use.
This signal is in the same clock domain as `clk_i`.
-It is high when OTBN is not running.
-The cycle after a write to {{< regref "CMD.start" >}}, the signal goes low.
-This remains low until the end of the operation (either from an {{< otbnInsnRef "ECALL" >}}) or an error, at which point it goes high again.
+The `idle_o` signal is high when OTBN [is idle](#design-details-operational-states), and low otherwise.
OTBN also exposes another version of the idle signal as `idle_otp_o`.
This works analogously, but is in the same clock domain as `clk_otp_i`.
@@ -713,27 +753,13 @@
- [Instruction memory]({{<relref "#design-details-secure-wipe-imem">}})
- [Internal state]({{<relref "#design-details-secure-wipe-internal">}})
-Secure wipe of data and instruction memories can be triggered on demand from a host software.
-In addition, full or partial secure wipe is triggered automatically by the OTBN in certain situations.
+The three forms of secure wipe can be triggered in different ways.
-OTBN does not signal any error while a secure wipe operation is in progress.
+A secure wipe of either the instruction or the data memory can be triggered from from host software by issuing a `SEC_WIPE_DMEM` or `SEC_WIPE_IMEM` [command](#design-details-command).
-#### Triggering Secure Wipe
+A secure wipe of instruction memory, data memory, and all internal state is performed automatically when handling a [fatal error](#design-details-fatal-errors).
-In the following situations OTBN itself initiates a full secure wipe:
-* The lifecycle controller asks for it through its escalation signal.
-* A fatal alert is issued.
- In this case, a full secure wipe is performed as a local action.
-
-The internal state secure wipe is automatically triggered when an OTBN operation completes, either successfully, or unsuccessfully due to a recoverable error.
-
-Host software can trigger a data and instruction memory secure wipe by writing `2'b11` to {{< regref "SEC_WIPE">}} (i.e. by setting both individual state wipe bits to 1).
-
-#### Completion of Secure Wipe {#design-details-secure-wipe-completion}
-
-During the secure wipe operation the {{< regref "STATUS.busy">}} flag is set to 1, indicating that the OTBN is busy.
-Once the operation is completed, an {{< regref "INTR_STATE.done" >}} interrupt is raised and {{< regref "STATUS.busy">}} is cleared.
-This effectively means that the host software will get a single done interrupt for a secure wipe operation, independent of how many SEC_WIPE bits the software wrote.
+A secure wipe of the internal state only is triggered automatically when OTBN [ends the software execution](#design-details-software-execution), either successfully, or unsuccessfully due to a [recoverable error](#design-details-recoverable-errors).
#### Data Memory (DMEM) Secure Wipe {#design-details-secure-wipe-dmem}
@@ -745,8 +771,7 @@
* Request new scrambling parameters from OTP.
The request takes multiple cycles to complete.
-Host software can initiate a data memory secure wipe by writing 1 to the {{< regref "SEC_WIPE.dmem">}} register field.
-If a secure wipe was triggered in this way, [completion]({{<relref "#design-details-secure-wipe-completion">}}) is signaled by raising an {{< regref "INTR_STATE.done" >}} interrupt.
+Host software can initiate a data memory secure wipe by [issuing the `SEC_WIPE_DMEM` command](#design-details-commands).
#### Instruction Memory (IMEM) Secure Wipe {#design-details-secure-wipe-imem}
@@ -758,8 +783,7 @@
* Request new scrambling parameters from OTP.
The request takes multiple cycles to complete.
-Host software can initiate an instruction memory secure wipe by writing 1 to the {{< regref "SEC_WIPE.imem">}} register field.
-If a secure wipe was triggered in this way, [completion]({{<relref "#design-details-secure-wipe-completion">}}) is signaled by raising an {{< regref "INTR_STATE.done" >}} interrupt.
+Host software can initiate a data memory secure wipe by [issuing the `SEC_WIPE_IMEM` command](#design-details-commands).
#### Internal State Secure Wipe {#design-details-secure-wipe-internal}
@@ -777,8 +801,7 @@
Loop and call stack pointers are reset.
-Host software can initiate an internal state secure wipe by writing 1 to the {{< regref "SEC_WIPE.internal">}} register field.
-If a secure wipe was triggered in this way, [completion]({{<relref "#design-details-secure-wipe-completion">}}) is signaled by raising an {{< regref "INTR_STATE.done" >}} interrupt.
+Host software cannot explicitly trigger an internal secure wipe; it is performed automatically at the end of an `EXECUTE` operation.
# Running applications on OTBN
@@ -792,7 +815,7 @@
1. Write the OTBN application binary to {{< regref "IMEM" >}}, starting at address 0.
2. Optional: Write constants and input arguments, as mandated by the calling convention of the loaded application, to {{< regref "DMEM" >}}.
-3. Start the operation on OTBN by writing `1` to {{< regref "CMD.start" >}}.
+3. Start the operation on OTBN by [issuing the `EXECUTE` command](#design-details-commands).
Now neither data nor instruction memory may be accessed from the host CPU.
After it has been started the OTBN application runs to completion without further interaction with the host.
4. Wait for the operation to complete (see below).
@@ -801,11 +824,11 @@
6. Optional: Retrieve results by reading {{< regref "DMEM" >}}, as mandated by the calling convention of the loaded application.
OTBN applications are run to completion.
-The host CPU can determine if an application has completed by either polling {{< regref "STATUS.busy">}} or listening for an interrupt.
+The host CPU can determine if an application has completed by either polling {{< regref "STATUS">}} or listening for an interrupt.
-* To poll for a completed operation, software should repeatedly read the {{< regref "STATUS.busy" >}} register.
- While the operation is in progress, {{< regref "STATUS.busy" >}} reads as `1`.
- The operation is completed if {{< regref "STATUS.busy" >}} is `0`.
+* To poll for a completed operation, software should repeatedly read the {{< regref "STATUS" >}} register.
+ While the operation is in progress, {{< regref "STATUS" >}} is non-zero.
+ The operation is complete if {{< regref "STATUS" >}} is `IDLE`.
* Alternatively, software can listen for the `done` interrupt to determine if the operation has completed.
The standard sequence of working with interrupts has to be followed, i.e. the interrupt has to be enabled, an interrupt service routine has to be registered, etc.
The [DIF]({{<relref "#dif" >}}) contains helpers to do so conveniently.
@@ -848,7 +871,7 @@
Passing data between the host CPU and OTBN is done through the data memory (DMEM).
No standard or required calling convention exists, every application is free to pass data in and out of OTBN in whatever format it finds convenient.
-All data passing must be done when OTBN is not running, as indicated by the {{< regref "STATUS.busy" >}} bit; during the OTBN operation both the instruction and the data memory are inaccessible from the host CPU.
+All data passing must be done when OTBN [is idle](#design-details-operational-states); otherwise both the instruction and the data memory are inaccessible from the host CPU.
## Returning from an application {#writing-otbn-applications-ecall}
@@ -859,7 +882,7 @@
- No more instructions are fetched or executed.
- A [secure wipe of internal state](#design-details-secure-wipe-internal) is performed.
- The {{< regref "ERR_BITS" >}} register is set to 0, indicating a successful operation.
-- The current operation is marked as completed by setting {{< regref "INTR_STATE.done" >}} and clearing {{< regref "STATUS.busy" >}}.
+- The current operation is marked as complete by setting {{< regref "INTR_STATE.done" >}} and clearing {{< regref "STATUS" >}}.
The DMEM can be used to pass data back to the host processor, e.g. a "return value" or an "exit code".
Refer to the section [Passing of data between the host CPU and OTBN]({{<relref "#writing-otbn-applications-datapassing" >}}) for more information.
diff --git a/hw/ip/otbn/dv/otbnsim/sim/constants.py b/hw/ip/otbn/dv/otbnsim/sim/constants.py
new file mode 100644
index 0000000..a8b576f
--- /dev/null
+++ b/hw/ip/otbn/dv/otbnsim/sim/constants.py
@@ -0,0 +1,34 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+from enum import IntEnum
+
+
+class Cmd(IntEnum):
+ '''Permitted values of the CMD register.'''
+ EXECUTE = 0x01
+ SEC_WIPE_DMEM = 0x02
+ SEC_WIPE_IMEM = 0x03
+
+
+class Status(IntEnum):
+ '''Permitted values of the STATUS register.'''
+ IDLE = 0x00
+ BUSY_EXECUTE = 0x01
+ BUSY_SEC_WIPE_DMEM = 0x02
+ BUSY_SEC_WIPE_IMEM = 0x03
+
+
+class ErrBits(IntEnum):
+ '''A copy of the list of bits in the ERR_BITS register.'''
+ BAD_DATA_ADDR = 1 << 0
+ BAD_INSN_ADDR = 1 << 1
+ CALL_STACK = 1 << 2
+ ILLEGAL_INSN = 1 << 3
+ LOOP = 1 << 4
+ FATAL_IMEM = 1 << 5
+ FATAL_DMEM = 1 << 6
+ FATAL_REG = 1 << 7
+ FATAL_ILLEGAL_BUS_ACCESS = 1 << 8
+ FATAL_LIFECYCLE_ESCALATION = 1 << 9
diff --git a/hw/ip/otbn/dv/otbnsim/sim/decode.py b/hw/ip/otbn/dv/otbnsim/sim/decode.py
index a2ba015..124ecd2 100644
--- a/hw/ip/otbn/dv/otbnsim/sim/decode.py
+++ b/hw/ip/otbn/dv/otbnsim/sim/decode.py
@@ -7,7 +7,7 @@
import struct
from typing import List, Optional, Iterator
-from .err_bits import ILLEGAL_INSN
+from .constants import ErrBits
from .isa import INSNS_FILE, OTBNInsn
from .insn import INSN_CLASSES
from .state import OTBNState
@@ -36,7 +36,7 @@
self._disasm = (pc, '?? 0x{:08x}'.format(raw))
def execute(self, state: OTBNState) -> Optional[Iterator[None]]:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return None
diff --git a/hw/ip/otbn/dv/otbnsim/sim/err_bits.py b/hw/ip/otbn/dv/otbnsim/sim/err_bits.py
deleted file mode 100644
index 6772f9d..0000000
--- a/hw/ip/otbn/dv/otbnsim/sim/err_bits.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-# A copy of the list of bits in the ERR_BITS register. This also appears in the
-# documentation and otbn_pkg.sv: we should probably be generating them from the
-# hjson every time.
-BAD_DATA_ADDR = 1 << 0
-BAD_INSN_ADDR = 1 << 1
-CALL_STACK = 1 << 2
-ILLEGAL_INSN = 1 << 3
-LOOP = 1 << 4
-FATAL_IMEM = 1 << 5
-FATAL_DMEM = 1 << 6
-FATAL_REG = 1 << 7
-FATAL_ILLEGAL_BUS_ACCESS = 1 << 8
-FATAL_LIFECYCLE_ESCALATION = 1 << 9
diff --git a/hw/ip/otbn/dv/otbnsim/sim/gpr.py b/hw/ip/otbn/dv/otbnsim/sim/gpr.py
index e2058c2..2e359bc 100644
--- a/hw/ip/otbn/dv/otbnsim/sim/gpr.py
+++ b/hw/ip/otbn/dv/otbnsim/sim/gpr.py
@@ -4,7 +4,7 @@
from typing import List
-from .err_bits import CALL_STACK
+from .constants import ErrBits
from .reg import Reg, RegFile
@@ -94,7 +94,7 @@
return self._x1.post_insn()
def err_bits(self) -> int:
- return CALL_STACK if self.err_flag else 0
+ return ErrBits.CALL_STACK if self.err_flag else 0
def commit(self) -> None:
super().commit()
diff --git a/hw/ip/otbn/dv/otbnsim/sim/insn.py b/hw/ip/otbn/dv/otbnsim/sim/insn.py
index 91c30c6..63c9ae2 100644
--- a/hw/ip/otbn/dv/otbnsim/sim/insn.py
+++ b/hw/ip/otbn/dv/otbnsim/sim/insn.py
@@ -4,13 +4,12 @@
from typing import Dict, Iterator, Optional
-from sim import err_bits
+from .constants import ErrBits
from .flags import FlagReg
from .isa import (OTBNInsn, RV32RegReg, RV32RegImm,
RV32ImmShift, insn_for_mnemonic, logical_byte_shift,
extract_quarter_word)
from .state import OTBNState
-from .err_bits import BAD_DATA_ADDR, ILLEGAL_INSN
class ADD(RV32RegReg):
@@ -192,7 +191,7 @@
addr = (base + self.offset) & ((1 << 32) - 1)
if not state.dmem.is_valid_32b_addr(addr):
- state.stop_at_end_of_cycle(BAD_DATA_ADDR)
+ state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
return
result = state.dmem.load_u32(addr)
@@ -218,7 +217,7 @@
value = state.gprs.get_reg(self.grs2).read_unsigned()
if not state.dmem.is_valid_32b_addr(addr):
- state.stop_at_end_of_cycle(BAD_DATA_ADDR)
+ state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
return
state.dmem.store_u32(addr, value)
@@ -304,7 +303,7 @@
def execute(self, state: OTBNState) -> Optional[Iterator[None]]:
if not state.csrs.check_idx(self.csr):
# Invalid CSR index. Stop with an illegal instruction error.
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
bits_to_set = state.gprs.get_reg(self.grs1).read_unsigned()
@@ -337,7 +336,7 @@
def execute(self, state: OTBNState) -> Optional[Iterator[None]]:
if not state.csrs.check_idx(self.csr):
# Invalid CSR index. Stop with an illegal instruction error.
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
new_val = state.gprs.get_reg(self.grs1).read_unsigned()
@@ -380,7 +379,7 @@
def execute(self, state: OTBNState) -> None:
num_iters = state.gprs.get_reg(self.grs).read_unsigned()
if num_iters == 0:
- state.stop_at_end_of_cycle(err_bits.LOOP)
+ state.stop_at_end_of_cycle(ErrBits.LOOP)
else:
state.loop_start(num_iters, self.bodysize)
@@ -396,7 +395,7 @@
def execute(self, state: OTBNState) -> None:
if self.iterations == 0:
- state.stop_at_end_of_cycle(err_bits.LOOP)
+ state.stop_at_end_of_cycle(ErrBits.LOOP)
else:
state.loop_start(self.iterations, self.bodysize)
@@ -924,18 +923,18 @@
grd_val = state.gprs.get_reg(self.grd).read_unsigned()
if grd_val > 31:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
if not state.dmem.is_valid_256b_addr(addr):
- state.stop_at_end_of_cycle(BAD_DATA_ADDR)
+ state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
return
wrd = grd_val & 0x1f
value = state.dmem.load_u256(addr)
if self.grs1_inc and self.grd_inc:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
if self.grd_inc:
@@ -970,15 +969,15 @@
grs2_val = state.gprs.get_reg(self.grs2).read_unsigned()
if self.grs1_inc and self.grs2_inc:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
if grs2_val > 31:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
if not state.dmem.is_valid_256b_addr(addr):
- state.stop_at_end_of_cycle(BAD_DATA_ADDR)
+ state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
return
wrs = grs2_val & 0x1f
@@ -1023,13 +1022,13 @@
grs_val = state.gprs.get_reg(self.grs).read_unsigned()
if self.grs_inc and self.grd_inc:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
if grd_val > 31:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
elif grs_val > 31:
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
else:
wrd = grd_val & 0x1f
wrs = grs_val & 0x1f
@@ -1058,7 +1057,7 @@
# The first, and possibly only, cycle of execution.
if not state.wsrs.check_idx(self.wsr):
# Invalid WSR index. Stop with an illegal instruction error.
- state.stop_at_end_of_cycle(ILLEGAL_INSN)
+ state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
if self.wsr == 0x1:
diff --git a/hw/ip/otbn/dv/otbnsim/sim/loop.py b/hw/ip/otbn/dv/otbnsim/sim/loop.py
index 217bf82..b584a7f 100644
--- a/hw/ip/otbn/dv/otbnsim/sim/loop.py
+++ b/hw/ip/otbn/dv/otbnsim/sim/loop.py
@@ -4,7 +4,7 @@
from typing import List, Optional
-from . import err_bits
+from .constants import ErrBits
from .trace import Trace
@@ -140,7 +140,7 @@
return None
def err_bits(self) -> int:
- return err_bits.LOOP if self.err_flag else 0
+ return ErrBits.LOOP if self.err_flag else 0
def changes(self) -> List[Trace]:
return self.trace
diff --git a/hw/ip/otbn/dv/otbnsim/sim/state.py b/hw/ip/otbn/dv/otbnsim/sim/state.py
index 43586ec..33d7788 100644
--- a/hw/ip/otbn/dv/otbnsim/sim/state.py
+++ b/hw/ip/otbn/dv/otbnsim/sim/state.py
@@ -8,7 +8,7 @@
from .csr import CSRFile
from .dmem import Dmem
-from .err_bits import BAD_INSN_ADDR
+from .constants import ErrBits, Status
from .ext_regs import OTBNExtRegs
from .flags import FlagReg
from .gpr import GPRs
@@ -155,7 +155,7 @@
def start(self) -> None:
'''Set the running flag and the ext_reg busy flag; perform state init'''
- self.ext_regs.set_bits('STATUS', 1 << 0)
+ self.ext_regs.write('STATUS', Status.BUSY_EXECUTE, True)
self.ext_regs.write('INSN_CNT', 0, True)
self.running = True
self._start_stall = True
@@ -203,8 +203,8 @@
# INTR_STATE is the interrupt state register. Bit 0 (which is being
# set) is the 'done' flag.
self.ext_regs.set_bits('INTR_STATE', 1 << 0)
- # STATUS is a status register. Bit 0 (being cleared) is the 'busy' flag
- self.ext_regs.clear_bits('STATUS', 1 << 0)
+ # STATUS is a status register. Return to idle.
+ self.ext_regs.write('STATUS', Status.IDLE, True)
# Make any error bits visible
self.ext_regs.write('ERR_BITS', self._err_bits, True)
@@ -262,7 +262,7 @@
# we've just checked for would squash the "next PC" check.
if not self.pending_halt:
if not self.is_next_pc_valid():
- self._err_bits |= BAD_INSN_ADDR
+ self._err_bits |= ErrBits.BAD_INSN_ADDR
self.pending_halt = True
def read_csr(self, idx: int) -> int:
diff --git a/hw/ip/otbn/dv/otbnsim/test/state_test.py b/hw/ip/otbn/dv/otbnsim/test/state_test.py
index 6186f78..8908971 100644
--- a/hw/ip/otbn/dv/otbnsim/test/state_test.py
+++ b/hw/ip/otbn/dv/otbnsim/test/state_test.py
@@ -6,7 +6,7 @@
import py
-import sim.err_bits as err_bits
+from sim.constants import ErrBits, Status
from testutil import prepare_sim_for_asm_str
@@ -24,14 +24,14 @@
assert sim.state.ext_regs.read('ERR_BITS', False) == 0
assert sim.state.ext_regs.read('FATAL_ALERT_CAUSE', False) == 0
- # The CMD register only contains the start field, which is write-only.
- assert sim.state.ext_regs.read('CMD', False) == 0
+ # The CMD register is write-only from software.
+ assert sim.state.ext_regs.read('CMD', from_hw=True) == 0
# Only INTR_STATE.done is set
assert sim.state.ext_regs.read('INTR_STATE', False) == (1 << 0)
- # STATUS.busy (the only field in this register) must be zero.
- assert sim.state.ext_regs.read('STATUS', False) == 0
+ # STATUS must be IDLE
+ assert sim.state.ext_regs.read('STATUS', False) == Status.IDLE
# START_ADDR should reflect the start address that was last written there
# when the simulation was started.
@@ -51,6 +51,6 @@
sim = prepare_sim_for_asm_str(invalid_jump_asm, tmpdir, start_addr=0)
sim.run(verbose=False, collect_stats=False)
- assert sim.state.ext_regs.read('ERR_BITS', False) == err_bits.BAD_INSN_ADDR
+ assert sim.state.ext_regs.read('ERR_BITS', False) == ErrBits.BAD_INSN_ADDR
assert sim.state.ext_regs.read('FATAL_ALERT_CAUSE', False) == 0
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_scoreboard.sv b/hw/ip/otbn/dv/uvm/env/otbn_scoreboard.sv
index f72299d..dea3365 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_scoreboard.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_scoreboard.sv
@@ -123,8 +123,8 @@
case (csr.get_name())
// Spot writes to the "cmd" register, which tell us to start
"cmd": begin
- // We start when we see a write that sets the "start" field of the register.
- if (csr_utils_pkg::get_field_val(cfg.ral.cmd.start, item.a_data)) begin
+ // We start the execution when we see a write of the START command.
+ if (item.a_data == 8'h01) begin
saw_start_tl_trans = 1'b1;
end
end
diff --git a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv
index aab914b..24d7dd8 100644
--- a/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv
+++ b/hw/ip/otbn/dv/uvm/env/seq_lib/otbn_base_vseq.sv
@@ -116,16 +116,13 @@
`DV_CHECK_FATAL(!running_)
running_ = 1'b1;
- // Set the "start" bit in cmd_val and write it to the "cmd" register to start OTBN.
- `DV_CHECK_FATAL(ral.cmd.start.get_n_bits == 1);
- cmd_val = 1 << ral.cmd.start.get_lsb_pos();
-
+ // Start OTBN by writing EXECUTE to the CMD register.
`uvm_info(`gfn, $sformatf("\n\t ----| Starting OTBN"), UVM_MEDIUM)
- csr_utils_pkg::csr_wr(ral.cmd, cmd_val);
+ csr_utils_pkg::csr_wr(ral.cmd, otbn_pkg::CmdExecute);
// Now wait until OTBN has finished
`uvm_info(`gfn, $sformatf("\n\t ----| Waiting for OTBN to finish"), UVM_MEDIUM)
- csr_utils_pkg::csr_spinwait(.ptr(ral.status.busy), .exp_data(1'b0));
+ csr_utils_pkg::csr_spinwait(.ptr(ral.status), .exp_data(otbn_pkg::StatusIdle));
`uvm_info(`gfn, $sformatf("\n\t ----| OTBN finished"), UVM_MEDIUM)
diff --git a/hw/ip/otbn/rtl/otbn.sv b/hw/ip/otbn/rtl/otbn.sv
index b7cceaf..6c8a58c 100644
--- a/hw/ip/otbn/rtl/otbn.sv
+++ b/hw/ip/otbn/rtl/otbn.sv
@@ -86,7 +86,7 @@
`ASSERT_INIT(DmemSizePowerOfTwo, 2**DmemAddrWidth == DmemSizeByte)
logic start_d, start_q;
- logic busy_d, busy_q;
+ logic busy_execute_d, busy_execute_q;
logic done;
logic illegal_bus_access_d, illegal_bus_access_q;
@@ -97,10 +97,6 @@
otbn_reg2hw_t reg2hw;
otbn_hw2reg_t hw2reg;
- // TODO: Connect up sec_wipe signals
- logic unused_sec_wipe;
- assign unused_sec_wipe = ^{reg2hw.sec_wipe};
-
// Bus device windows, as specified in otbn.hjson
typedef enum logic {
TlWinImem = 1'b0,
@@ -113,9 +109,8 @@
// Inter-module signals ======================================================
- // TODO: Better define what "idle" means -- only the core, or also the
- // register interface?
- assign idle_o = ~busy_q;
+ // TODO: Use STATUS == IDLE here.
+ assign idle_o = ~busy_execute_q;
// TODO: These two signals aren't technically in the same clock domain. Sort out how we do the
// signalling properly.
@@ -317,7 +312,7 @@
// Mux core and bus access into IMEM
- assign imem_access_core = busy_q | start_q;
+ assign imem_access_core = busy_execute_q | start_q;
assign imem_req = imem_access_core ? imem_req_core : imem_req_bus;
assign imem_write = imem_access_core ? imem_write_core : imem_write_bus;
@@ -514,7 +509,7 @@
);
// Mux core and bus access into dmem
- assign dmem_access_core = busy_q;
+ assign dmem_access_core = busy_execute_q;
assign dmem_req = dmem_access_core ? dmem_req_core : dmem_req_bus;
assign dmem_write = dmem_access_core ? dmem_write_core : dmem_write_bus;
@@ -577,9 +572,8 @@
reg_bus_integrity_error);
// CMD register
- // CMD.start ("start" is omitted by reggen since it is the only field).
// start is flopped to avoid long timing paths from the TL fabric into OTBN internals.
- assign start_d = reg2hw.cmd.qe & reg2hw.cmd.q;
+ assign start_d = reg2hw.cmd.qe & (reg2hw.cmd.q == CmdExecute);
assign illegal_bus_access_d = dmem_illegal_bus_access | imem_illegal_bus_access;
// Flop `illegal_bus_access_q` so we know an illegal bus access has happened and to break a timing
@@ -595,8 +589,13 @@
end
// STATUS register
- // STATUS.busy ("busy" is omitted by reggen since since it is the only field)
- assign hw2reg.status.d = busy_q;
+ always_comb begin
+ unique case (1'b1)
+ busy_execute_q: hw2reg.status.d = StatusBusyExecute;
+ // TODO: Add other busy flags, and assert onehot encoding.
+ default: hw2reg.status.d = StatusIdle;
+ endcase
+ end
// ERR_BITS register
// The error bits for an OTBN operation get stored on the cycle that done is
@@ -735,12 +734,12 @@
always_ff @(posedge clk_i or negedge rst_n) begin
if (!rst_n) begin
- busy_q <= 1'b0;
+ busy_execute_q <= 1'b0;
end else begin
- busy_q <= busy_d;
+ busy_execute_q <= busy_execute_d;
end
end
- assign busy_d = (busy_q | start_d) & ~done;
+ assign busy_execute_d = (busy_execute_q | start_d) & ~done;
`ifdef OTBN_BUILD_MODEL
// Build both model and RTL implementation into the design, and switch at runtime through a
diff --git a/hw/ip/otbn/rtl/otbn_pkg.sv b/hw/ip/otbn/rtl/otbn_pkg.sv
index 6707749..c17fc85 100644
--- a/hw/ip/otbn/rtl/otbn_pkg.sv
+++ b/hw/ip/otbn/rtl/otbn_pkg.sv
@@ -50,6 +50,21 @@
RegFileFPGA = 1 // FPGA implmentation, does infer RAM primitives.
} regfile_e;
+ // Command to execute. See the CMD register description in otbn.hjson for details.
+ typedef enum logic [7:0] {
+ CmdExecute = 8'h01,
+ CmdSecWipeDmem = 8'h02,
+ CmdSecWipeImem = 8'h03
+ } cmd_e;
+
+ // Status register values. See the STATUS register description in otbn.hjson for details.
+ typedef enum logic [7:0] {
+ StatusIdle = 8'h00,
+ StatusBusyExecute = 8'h01,
+ StatusBusySecWipeDmem = 8'h02,
+ StatusBusySecWipeImem = 8'h03
+ } status_e;
+
// Error bits
//
// Note: These errors are duplicated in other places. If updating them here, update those too.
diff --git a/hw/ip/otbn/rtl/otbn_reg_pkg.sv b/hw/ip/otbn/rtl/otbn_reg_pkg.sv
index cca1fc1..de8fab8 100644
--- a/hw/ip/otbn/rtl/otbn_reg_pkg.sv
+++ b/hw/ip/otbn/rtl/otbn_reg_pkg.sv
@@ -41,7 +41,7 @@
} otbn_reg2hw_alert_test_reg_t;
typedef struct packed {
- logic q;
+ logic [7:0] q;
logic qe;
} otbn_reg2hw_cmd_reg_t;
@@ -50,21 +50,12 @@
} otbn_reg2hw_start_addr_reg_t;
typedef struct packed {
- struct packed {
- logic q;
- } dmem;
- struct packed {
- logic q;
- } imem;
- } otbn_reg2hw_sec_wipe_reg_t;
-
- typedef struct packed {
logic d;
logic de;
} otbn_hw2reg_intr_state_reg_t;
typedef struct packed {
- logic d;
+ logic [7:0] d;
} otbn_hw2reg_status_reg_t;
typedef struct packed {
@@ -143,19 +134,18 @@
// Register -> HW type
typedef struct packed {
- otbn_reg2hw_intr_state_reg_t intr_state; // [43:43]
- otbn_reg2hw_intr_enable_reg_t intr_enable; // [42:42]
- otbn_reg2hw_intr_test_reg_t intr_test; // [41:40]
- otbn_reg2hw_alert_test_reg_t alert_test; // [39:36]
- otbn_reg2hw_cmd_reg_t cmd; // [35:34]
- otbn_reg2hw_start_addr_reg_t start_addr; // [33:2]
- otbn_reg2hw_sec_wipe_reg_t sec_wipe; // [1:0]
+ otbn_reg2hw_intr_state_reg_t intr_state; // [48:48]
+ otbn_reg2hw_intr_enable_reg_t intr_enable; // [47:47]
+ otbn_reg2hw_intr_test_reg_t intr_test; // [46:45]
+ otbn_reg2hw_alert_test_reg_t alert_test; // [44:41]
+ otbn_reg2hw_cmd_reg_t cmd; // [40:32]
+ otbn_reg2hw_start_addr_reg_t start_addr; // [31:0]
} otbn_reg2hw_t;
// HW -> register type
typedef struct packed {
- otbn_hw2reg_intr_state_reg_t intr_state; // [66:65]
- otbn_hw2reg_status_reg_t status; // [64:64]
+ otbn_hw2reg_intr_state_reg_t intr_state; // [73:72]
+ otbn_hw2reg_status_reg_t status; // [71:64]
otbn_hw2reg_err_bits_reg_t err_bits; // [63:44]
otbn_hw2reg_fatal_alert_cause_reg_t fatal_alert_cause; // [43:32]
otbn_hw2reg_insn_cnt_reg_t insn_cnt; // [31:0]
@@ -171,8 +161,7 @@
parameter logic [BlockAw-1:0] OTBN_ERR_BITS_OFFSET = 16'h 18;
parameter logic [BlockAw-1:0] OTBN_START_ADDR_OFFSET = 16'h 1c;
parameter logic [BlockAw-1:0] OTBN_FATAL_ALERT_CAUSE_OFFSET = 16'h 20;
- parameter logic [BlockAw-1:0] OTBN_SEC_WIPE_OFFSET = 16'h 24;
- parameter logic [BlockAw-1:0] OTBN_INSN_CNT_OFFSET = 16'h 28;
+ parameter logic [BlockAw-1:0] OTBN_INSN_CNT_OFFSET = 16'h 24;
// Reset values for hwext registers and their fields
parameter logic [0:0] OTBN_INTR_TEST_RESVAL = 1'h 0;
@@ -180,8 +169,10 @@
parameter logic [1:0] OTBN_ALERT_TEST_RESVAL = 2'h 0;
parameter logic [0:0] OTBN_ALERT_TEST_FATAL_RESVAL = 1'h 0;
parameter logic [0:0] OTBN_ALERT_TEST_RECOV_RESVAL = 1'h 0;
- parameter logic [0:0] OTBN_CMD_RESVAL = 1'h 0;
- parameter logic [0:0] OTBN_STATUS_RESVAL = 1'h 0;
+ parameter logic [7:0] OTBN_CMD_RESVAL = 8'h 0;
+ parameter logic [7:0] OTBN_CMD_CMD_RESVAL = 8'h 0;
+ parameter logic [7:0] OTBN_STATUS_RESVAL = 8'h 0;
+ parameter logic [7:0] OTBN_STATUS_STATUS_RESVAL = 8'h 0;
parameter logic [31:0] OTBN_INSN_CNT_RESVAL = 32'h 0;
parameter logic [31:0] OTBN_INSN_CNT_INSN_CNT_RESVAL = 32'h 0;
@@ -202,23 +193,21 @@
OTBN_ERR_BITS,
OTBN_START_ADDR,
OTBN_FATAL_ALERT_CAUSE,
- OTBN_SEC_WIPE,
OTBN_INSN_CNT
} otbn_id_e;
// Register width information to check illegal writes
- parameter logic [3:0] OTBN_PERMIT [11] = '{
- 4'b 0001, // index[ 0] OTBN_INTR_STATE
- 4'b 0001, // index[ 1] OTBN_INTR_ENABLE
- 4'b 0001, // index[ 2] OTBN_INTR_TEST
- 4'b 0001, // index[ 3] OTBN_ALERT_TEST
- 4'b 0001, // index[ 4] OTBN_CMD
- 4'b 0001, // index[ 5] OTBN_STATUS
- 4'b 0011, // index[ 6] OTBN_ERR_BITS
- 4'b 1111, // index[ 7] OTBN_START_ADDR
- 4'b 0001, // index[ 8] OTBN_FATAL_ALERT_CAUSE
- 4'b 0001, // index[ 9] OTBN_SEC_WIPE
- 4'b 1111 // index[10] OTBN_INSN_CNT
+ parameter logic [3:0] OTBN_PERMIT [10] = '{
+ 4'b 0001, // index[0] OTBN_INTR_STATE
+ 4'b 0001, // index[1] OTBN_INTR_ENABLE
+ 4'b 0001, // index[2] OTBN_INTR_TEST
+ 4'b 0001, // index[3] OTBN_ALERT_TEST
+ 4'b 0001, // index[4] OTBN_CMD
+ 4'b 0001, // index[5] OTBN_STATUS
+ 4'b 0011, // index[6] OTBN_ERR_BITS
+ 4'b 1111, // index[7] OTBN_START_ADDR
+ 4'b 0001, // index[8] OTBN_FATAL_ALERT_CAUSE
+ 4'b 1111 // index[9] OTBN_INSN_CNT
};
endpackage
diff --git a/hw/ip/otbn/rtl/otbn_reg_top.sv b/hw/ip/otbn/rtl/otbn_reg_top.sv
index 3e0010e..c6cd125 100644
--- a/hw/ip/otbn/rtl/otbn_reg_top.sv
+++ b/hw/ip/otbn/rtl/otbn_reg_top.sv
@@ -173,9 +173,9 @@
logic alert_test_fatal_wd;
logic alert_test_recov_wd;
logic cmd_we;
- logic cmd_wd;
+ logic [7:0] cmd_wd;
logic status_re;
- logic status_qs;
+ logic [7:0] status_qs;
logic err_bits_bad_data_addr_qs;
logic err_bits_bad_insn_addr_qs;
logic err_bits_call_stack_qs;
@@ -194,9 +194,6 @@
logic fatal_alert_cause_reg_error_qs;
logic fatal_alert_cause_illegal_bus_access_qs;
logic fatal_alert_cause_lifecycle_escalation_qs;
- logic sec_wipe_we;
- logic sec_wipe_dmem_wd;
- logic sec_wipe_imem_wd;
logic insn_cnt_re;
logic [31:0] insn_cnt_qs;
@@ -306,7 +303,7 @@
// R[cmd]: V(True)
prim_subreg_ext #(
- .DW (1)
+ .DW (8)
) u_cmd (
.re (1'b0),
.we (cmd_we),
@@ -322,7 +319,7 @@
// R[status]: V(True)
prim_subreg_ext #(
- .DW (1)
+ .DW (8)
) u_status (
.re (status_re),
.we (1'b0),
@@ -782,60 +779,6 @@
);
- // R[sec_wipe]: V(False)
-
- // F[dmem]: 0:0
- prim_subreg #(
- .DW (1),
- .SwAccess(prim_subreg_pkg::SwAccessWO),
- .RESVAL (1'h0)
- ) u_sec_wipe_dmem (
- .clk_i (clk_i),
- .rst_ni (rst_ni),
-
- // from register interface
- .we (sec_wipe_we),
- .wd (sec_wipe_dmem_wd),
-
- // from internal hardware
- .de (1'b0),
- .d ('0),
-
- // to internal hardware
- .qe (),
- .q (reg2hw.sec_wipe.dmem.q),
-
- // to register interface (read)
- .qs ()
- );
-
-
- // F[imem]: 1:1
- prim_subreg #(
- .DW (1),
- .SwAccess(prim_subreg_pkg::SwAccessWO),
- .RESVAL (1'h0)
- ) u_sec_wipe_imem (
- .clk_i (clk_i),
- .rst_ni (rst_ni),
-
- // from register interface
- .we (sec_wipe_we),
- .wd (sec_wipe_imem_wd),
-
- // from internal hardware
- .de (1'b0),
- .d ('0),
-
- // to internal hardware
- .qe (),
- .q (reg2hw.sec_wipe.imem.q),
-
- // to register interface (read)
- .qs ()
- );
-
-
// R[insn_cnt]: V(True)
prim_subreg_ext #(
@@ -854,20 +797,19 @@
- logic [10:0] addr_hit;
+ logic [9:0] addr_hit;
always_comb begin
addr_hit = '0;
- addr_hit[ 0] = (reg_addr == OTBN_INTR_STATE_OFFSET);
- addr_hit[ 1] = (reg_addr == OTBN_INTR_ENABLE_OFFSET);
- addr_hit[ 2] = (reg_addr == OTBN_INTR_TEST_OFFSET);
- addr_hit[ 3] = (reg_addr == OTBN_ALERT_TEST_OFFSET);
- addr_hit[ 4] = (reg_addr == OTBN_CMD_OFFSET);
- addr_hit[ 5] = (reg_addr == OTBN_STATUS_OFFSET);
- addr_hit[ 6] = (reg_addr == OTBN_ERR_BITS_OFFSET);
- addr_hit[ 7] = (reg_addr == OTBN_START_ADDR_OFFSET);
- addr_hit[ 8] = (reg_addr == OTBN_FATAL_ALERT_CAUSE_OFFSET);
- addr_hit[ 9] = (reg_addr == OTBN_SEC_WIPE_OFFSET);
- addr_hit[10] = (reg_addr == OTBN_INSN_CNT_OFFSET);
+ addr_hit[0] = (reg_addr == OTBN_INTR_STATE_OFFSET);
+ addr_hit[1] = (reg_addr == OTBN_INTR_ENABLE_OFFSET);
+ addr_hit[2] = (reg_addr == OTBN_INTR_TEST_OFFSET);
+ addr_hit[3] = (reg_addr == OTBN_ALERT_TEST_OFFSET);
+ addr_hit[4] = (reg_addr == OTBN_CMD_OFFSET);
+ addr_hit[5] = (reg_addr == OTBN_STATUS_OFFSET);
+ addr_hit[6] = (reg_addr == OTBN_ERR_BITS_OFFSET);
+ addr_hit[7] = (reg_addr == OTBN_START_ADDR_OFFSET);
+ addr_hit[8] = (reg_addr == OTBN_FATAL_ALERT_CAUSE_OFFSET);
+ addr_hit[9] = (reg_addr == OTBN_INSN_CNT_OFFSET);
end
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
@@ -875,17 +817,16 @@
// Check sub-word write is permitted
always_comb begin
wr_err = (reg_we &
- ((addr_hit[ 0] & (|(OTBN_PERMIT[ 0] & ~reg_be))) |
- (addr_hit[ 1] & (|(OTBN_PERMIT[ 1] & ~reg_be))) |
- (addr_hit[ 2] & (|(OTBN_PERMIT[ 2] & ~reg_be))) |
- (addr_hit[ 3] & (|(OTBN_PERMIT[ 3] & ~reg_be))) |
- (addr_hit[ 4] & (|(OTBN_PERMIT[ 4] & ~reg_be))) |
- (addr_hit[ 5] & (|(OTBN_PERMIT[ 5] & ~reg_be))) |
- (addr_hit[ 6] & (|(OTBN_PERMIT[ 6] & ~reg_be))) |
- (addr_hit[ 7] & (|(OTBN_PERMIT[ 7] & ~reg_be))) |
- (addr_hit[ 8] & (|(OTBN_PERMIT[ 8] & ~reg_be))) |
- (addr_hit[ 9] & (|(OTBN_PERMIT[ 9] & ~reg_be))) |
- (addr_hit[10] & (|(OTBN_PERMIT[10] & ~reg_be)))));
+ ((addr_hit[0] & (|(OTBN_PERMIT[0] & ~reg_be))) |
+ (addr_hit[1] & (|(OTBN_PERMIT[1] & ~reg_be))) |
+ (addr_hit[2] & (|(OTBN_PERMIT[2] & ~reg_be))) |
+ (addr_hit[3] & (|(OTBN_PERMIT[3] & ~reg_be))) |
+ (addr_hit[4] & (|(OTBN_PERMIT[4] & ~reg_be))) |
+ (addr_hit[5] & (|(OTBN_PERMIT[5] & ~reg_be))) |
+ (addr_hit[6] & (|(OTBN_PERMIT[6] & ~reg_be))) |
+ (addr_hit[7] & (|(OTBN_PERMIT[7] & ~reg_be))) |
+ (addr_hit[8] & (|(OTBN_PERMIT[8] & ~reg_be))) |
+ (addr_hit[9] & (|(OTBN_PERMIT[9] & ~reg_be)))));
end
assign intr_state_we = addr_hit[0] & reg_we & !reg_error;
@@ -903,17 +844,12 @@
assign alert_test_recov_wd = reg_wdata[1];
assign cmd_we = addr_hit[4] & reg_we & !reg_error;
- assign cmd_wd = reg_wdata[0];
+ assign cmd_wd = reg_wdata[7:0];
assign status_re = addr_hit[5] & reg_re & !reg_error;
assign start_addr_we = addr_hit[7] & reg_we & !reg_error;
assign start_addr_wd = reg_wdata[31:0];
- assign sec_wipe_we = addr_hit[9] & reg_we & !reg_error;
-
- assign sec_wipe_dmem_wd = reg_wdata[0];
-
- assign sec_wipe_imem_wd = reg_wdata[1];
- assign insn_cnt_re = addr_hit[10] & reg_re & !reg_error;
+ assign insn_cnt_re = addr_hit[9] & reg_re & !reg_error;
// Read data return
always_comb begin
@@ -937,11 +873,11 @@
end
addr_hit[4]: begin
- reg_rdata_next[0] = '0;
+ reg_rdata_next[7:0] = '0;
end
addr_hit[5]: begin
- reg_rdata_next[0] = status_qs;
+ reg_rdata_next[7:0] = status_qs;
end
addr_hit[6]: begin
@@ -971,11 +907,6 @@
end
addr_hit[9]: begin
- reg_rdata_next[0] = '0;
- reg_rdata_next[1] = '0;
- end
-
- addr_hit[10]: begin
reg_rdata_next[31:0] = insn_cnt_qs;
end
diff --git a/sw/device/lib/dif/dif_otbn.c b/sw/device/lib/dif/dif_otbn.c
index bef2a76..44d0e21 100644
--- a/sw/device/lib/dif/dif_otbn.c
+++ b/sw/device/lib/dif/dif_otbn.c
@@ -214,8 +214,8 @@
return kDifOtbnOk;
}
-dif_otbn_result_t dif_otbn_start(const dif_otbn_t *otbn,
- unsigned int start_addr) {
+dif_otbn_result_t dif_otbn_set_start_addr(const dif_otbn_t *otbn,
+ unsigned int start_addr) {
if (otbn == NULL || start_addr % sizeof(uint32_t) != 0 ||
start_addr >= OTBN_IMEM_SIZE_BYTES) {
return kDifOtbnBadArg;
@@ -223,20 +223,27 @@
mmio_region_write32(otbn->base_addr, OTBN_START_ADDR_REG_OFFSET, start_addr);
- uint32_t cmd_reg_val = 0x0u;
- cmd_reg_val = bitfield_bit32_write(cmd_reg_val, OTBN_CMD_START_BIT, true);
- mmio_region_write32(otbn->base_addr, OTBN_CMD_REG_OFFSET, cmd_reg_val);
+ return kDifOtbnOk;
+}
+
+dif_otbn_result_t dif_otbn_write_cmd(const dif_otbn_t *otbn,
+ dif_otbn_cmd_t cmd) {
+ if (otbn == NULL) {
+ return kDifOtbnBadArg;
+ }
+
+ mmio_region_write32(otbn->base_addr, OTBN_CMD_REG_OFFSET, cmd);
return kDifOtbnOk;
}
-dif_otbn_result_t dif_otbn_is_busy(const dif_otbn_t *otbn, bool *busy) {
- if (otbn == NULL || busy == NULL) {
+dif_otbn_result_t dif_otbn_get_status(const dif_otbn_t *otbn,
+ dif_otbn_status_t *status) {
+ if (otbn == NULL || status == NULL) {
return kDifOtbnBadArg;
}
- uint32_t status = mmio_region_read32(otbn->base_addr, OTBN_STATUS_REG_OFFSET);
- *busy = bitfield_bit32_read(status, OTBN_STATUS_BUSY_BIT);
+ *status = mmio_region_read32(otbn->base_addr, OTBN_STATUS_REG_OFFSET);
return kDifOtbnOk;
}
diff --git a/sw/device/lib/dif/dif_otbn.h b/sw/device/lib/dif/dif_otbn.h
index ff6dc54..5868e8d 100644
--- a/sw/device/lib/dif/dif_otbn.h
+++ b/sw/device/lib/dif/dif_otbn.h
@@ -66,6 +66,25 @@
} dif_otbn_result_t;
/**
+ * OTBN commands
+ */
+typedef enum dif_otbn_cmd {
+ kDifOtbnCmdExecute = 0x01,
+ kDifOtbnCmdSecWipeDmem = 0x02,
+ kDifOtbnCmdSecWipeImem = 0x03,
+} dif_otbn_cmd_t;
+
+/**
+ * OTBN status
+ */
+typedef enum dif_otbn_status {
+ kDifOtbnStatusIdle = 0x00,
+ kDifOtbnStatusBusyExecute = 0x01,
+ kDifOtbnStatusBusySecWipeDmem = 0x02,
+ kDifOtbnStatusBusySecWipeImem = 0x03,
+} dif_otbn_status_t;
+
+/**
* OTBN Errors
*
* OTBN uses a bitfield to indicate which errors have been seen. Multiple errors
@@ -232,25 +251,36 @@
dif_otbn_interrupt_t irq_type);
/**
- * Start the execution of the application loaded into OTBN at the start address.
+ * Set the start address of the execution.
*
- * @param otbn OTBN instance
+ * @param otbn OTBN instance.
* @param start_addr The IMEM byte address to start the execution at.
* @return `kDifOtbnBadArg` if `otbn` is `NULL` or `start_addr` is invalid,
* `kDifOtbnOk` otherwise.
*/
-dif_otbn_result_t dif_otbn_start(const dif_otbn_t *otbn,
- unsigned int start_addr);
+dif_otbn_result_t dif_otbn_set_start_addr(const dif_otbn_t *otbn,
+ unsigned int start_addr);
/**
- * Is OTBN busy executing an application?
+ * Start an operation by issuing a command.
+ *
+ * @param otbn OTBN instance.
+ * @param cmd The command.
+ * @return `kDifOtbnBadArg` if `otbn` is `NULL`, `kDifOtbnOk` otherwise.
+ */
+dif_otbn_result_t dif_otbn_write_cmd(const dif_otbn_t *otbn,
+ dif_otbn_cmd_t cmd);
+
+/**
+ * Gets the current status of OTBN.
*
* @param otbn OTBN instance
- * @param[out] busy OTBN is busy
- * @return `kDifOtbnBadArg` if `otbn` or `busy` is `NULL`,
+ * @param[out] status OTBN status
+ * @return `kDifOtbnBadArg` if `otbn` or `status` is `NULL`,
* `kDifOtbnOk` otherwise.
*/
-dif_otbn_result_t dif_otbn_is_busy(const dif_otbn_t *otbn, bool *busy);
+dif_otbn_result_t dif_otbn_get_status(const dif_otbn_t *otbn,
+ dif_otbn_status_t *status);
/**
* Get the error bits set by the device if the operation failed.
diff --git a/sw/device/lib/dif/dif_otbn_unittest.cc b/sw/device/lib/dif/dif_otbn_unittest.cc
index f059c1a..ec54df1 100644
--- a/sw/device/lib/dif/dif_otbn_unittest.cc
+++ b/sw/device/lib/dif/dif_otbn_unittest.cc
@@ -199,75 +199,77 @@
EXPECT_EQ(dif_otbn_irq_force(&dif_otbn_, kDifOtbnInterruptDone), kDifOtbnOk);
}
-class StartTest : public OtbnTest {};
+class SetStartAddrTest : public OtbnTest {};
-TEST_F(StartTest, NullArgs) {
- EXPECT_EQ(dif_otbn_start(nullptr, 0), kDifOtbnBadArg);
+TEST_F(SetStartAddrTest, NullArgs) {
+ EXPECT_EQ(dif_otbn_set_start_addr(nullptr, 0), kDifOtbnBadArg);
}
-TEST_F(StartTest, BadStartAddress) {
+TEST_F(SetStartAddrTest, BadStartAddress) {
// Must be 4-byte aligned.
- EXPECT_EQ(dif_otbn_start(&dif_otbn_, 1), kDifOtbnBadArg);
+ EXPECT_EQ(dif_otbn_set_start_addr(&dif_otbn_, 1), kDifOtbnBadArg);
- EXPECT_EQ(dif_otbn_start(&dif_otbn_, 2), kDifOtbnBadArg);
+ EXPECT_EQ(dif_otbn_set_start_addr(&dif_otbn_, 2), kDifOtbnBadArg);
// Valid addresses (ignoring alignment): 0 .. (OTBN_IMEM_SIZE_BYTES - 1)
- EXPECT_EQ(dif_otbn_start(&dif_otbn_, OTBN_IMEM_SIZE_BYTES), kDifOtbnBadArg);
+ EXPECT_EQ(dif_otbn_set_start_addr(&dif_otbn_, OTBN_IMEM_SIZE_BYTES),
+ kDifOtbnBadArg);
- EXPECT_EQ(dif_otbn_start(&dif_otbn_, OTBN_IMEM_SIZE_BYTES + 32),
+ EXPECT_EQ(dif_otbn_set_start_addr(&dif_otbn_, OTBN_IMEM_SIZE_BYTES + 32),
kDifOtbnBadArg);
}
-TEST_F(StartTest, Success) {
+TEST_F(SetStartAddrTest, Success) {
// Test assumption.
ASSERT_GE(OTBN_IMEM_SIZE_BYTES, 8);
// Write start address.
EXPECT_WRITE32(OTBN_START_ADDR_REG_OFFSET, 4);
- // Set start command bit.
- EXPECT_WRITE32(OTBN_CMD_REG_OFFSET, {{OTBN_CMD_START_BIT, 1}});
-
- EXPECT_EQ(dif_otbn_start(&dif_otbn_, 4), kDifOtbnOk);
+ EXPECT_EQ(dif_otbn_set_start_addr(&dif_otbn_, 4), kDifOtbnOk);
}
-class IsBusyTest : public OtbnTest {};
+class WriteCmdTest : public OtbnTest {};
-TEST_F(IsBusyTest, NullArgs) {
- bool busy;
-
- EXPECT_EQ(dif_otbn_is_busy(nullptr, nullptr), kDifOtbnBadArg);
-
- EXPECT_EQ(dif_otbn_is_busy(&dif_otbn_, nullptr), kDifOtbnBadArg);
-
- // Also check for freedom from side effects in `busy`.
- busy = false;
- EXPECT_EQ(dif_otbn_is_busy(nullptr, &busy), kDifOtbnBadArg);
- EXPECT_EQ(busy, false);
-
- busy = true;
- EXPECT_EQ(dif_otbn_is_busy(nullptr, &busy), kDifOtbnBadArg);
- EXPECT_EQ(busy, true);
+TEST_F(WriteCmdTest, NullArgs) {
+ EXPECT_EQ(dif_otbn_write_cmd(nullptr, kDifOtbnCmdExecute), kDifOtbnBadArg);
}
-TEST_F(IsBusyTest, Success) {
- EXPECT_READ32(OTBN_STATUS_REG_OFFSET, {{OTBN_STATUS_BUSY_BIT, true}});
+TEST_F(WriteCmdTest, Success) {
+ // Set EXECUTE command.
+ EXPECT_WRITE32(OTBN_CMD_REG_OFFSET, kDifOtbnCmdExecute);
- bool busy = false;
- EXPECT_EQ(dif_otbn_is_busy(&dif_otbn_, &busy), kDifOtbnOk);
- EXPECT_EQ(busy, true);
+ EXPECT_EQ(dif_otbn_write_cmd(&dif_otbn_, kDifOtbnCmdExecute), kDifOtbnOk);
+}
+
+class GetStatusTest : public OtbnTest {};
+
+TEST_F(GetStatusTest, NullArgs) {
+ EXPECT_EQ(dif_otbn_get_status(nullptr, nullptr), kDifOtbnBadArg);
+
+ EXPECT_EQ(dif_otbn_get_status(&dif_otbn_, nullptr), kDifOtbnBadArg);
+
+ dif_otbn_status_t status = kDifOtbnStatusBusySecWipeDmem;
+ EXPECT_EQ(dif_otbn_get_status(nullptr, &status), kDifOtbnBadArg);
+ EXPECT_EQ(status, kDifOtbnStatusBusySecWipeDmem);
+}
+
+TEST_F(GetStatusTest, Success) {
+ EXPECT_READ32(OTBN_STATUS_REG_OFFSET, kDifOtbnStatusBusyExecute);
+
+ dif_otbn_status_t status;
+ EXPECT_EQ(dif_otbn_get_status(&dif_otbn_, &status), kDifOtbnOk);
+ EXPECT_EQ(status, kDifOtbnStatusBusyExecute);
}
class GetErrBitsTest : public OtbnTest {};
TEST_F(GetErrBitsTest, NullArgs) {
- dif_otbn_err_bits_t err_bits;
-
EXPECT_EQ(dif_otbn_get_err_bits(nullptr, nullptr), kDifOtbnBadArg);
EXPECT_EQ(dif_otbn_get_err_bits(&dif_otbn_, nullptr), kDifOtbnBadArg);
- err_bits = kDifOtbnErrBitsBadDataAddr;
+ dif_otbn_err_bits_t err_bits = kDifOtbnErrBitsBadDataAddr;
EXPECT_EQ(dif_otbn_get_err_bits(nullptr, &err_bits), kDifOtbnBadArg);
EXPECT_EQ(err_bits, kDifOtbnErrBitsBadDataAddr);
}
diff --git a/sw/device/lib/runtime/otbn.c b/sw/device/lib/runtime/otbn.c
index 2e721c4..8fa4246 100644
--- a/sw/device/lib/runtime/otbn.c
+++ b/sw/device/lib/runtime/otbn.c
@@ -43,9 +43,11 @@
otbn_result_t otbn_busy_wait_for_done(otbn_t *ctx) {
bool busy = true;
while (busy) {
- if (dif_otbn_is_busy(&ctx->dif, &busy) != kDifOtbnOk) {
+ dif_otbn_status_t status;
+ if (dif_otbn_get_status(&ctx->dif, &status) != kDifOtbnOk) {
return kOtbnError;
}
+ busy = status != kDifOtbnStatusIdle;
}
dif_otbn_err_bits_t err_bits;
@@ -53,7 +55,7 @@
return kOtbnError;
}
if (err_bits != kDifOtbnErrBitsNoError) {
- return kOtbnExecutionFailed;
+ return kOtbnOperationFailed;
}
return kOtbnOk;
}
@@ -115,7 +117,11 @@
return result;
}
- if (dif_otbn_start(&ctx->dif, func_imem_addr) != kDifOtbnOk) {
+ if (dif_otbn_set_start_addr(&ctx->dif, func_imem_addr) != kDifOtbnOk) {
+ return kOtbnError;
+ }
+
+ if (dif_otbn_write_cmd(&ctx->dif, kDifOtbnCmdExecute) != kDifOtbnOk) {
return kOtbnError;
}
diff --git a/sw/device/lib/runtime/otbn.h b/sw/device/lib/runtime/otbn.h
index 0082681..0017ca3 100644
--- a/sw/device/lib/runtime/otbn.h
+++ b/sw/device/lib/runtime/otbn.h
@@ -67,12 +67,12 @@
*/
kOtbnBadArg = 2,
/**
- * The execution of the application on OTBN failed.
+ * The operation performed on OTBN failed.
*
* More specific error information can be obtained with
* `dif_otbn_get_err_code()`.
*/
- kOtbnExecutionFailed = 3,
+ kOtbnOperationFailed = 3,
} otbn_result_t;
/**
@@ -191,7 +191,9 @@
otbn_result_t otbn_call_function(otbn_t *ctx, otbn_ptr_t func);
/**
- * Busy waits for OTBN to be done with its operation.
+ * Busy waits for OTBN to be done with the current operation.
+ *
+ * After an operation, triggered by a command, OTBN is back in idle state.
*
* @param ctx The context object.
* @return The result of the operation.
diff --git a/sw/device/silicon_creator/lib/drivers/otbn.c b/sw/device/silicon_creator/lib/drivers/otbn.c
index be2babe..d1c21a2 100644
--- a/sw/device/silicon_creator/lib/drivers/otbn.c
+++ b/sw/device/silicon_creator/lib/drivers/otbn.c
@@ -62,16 +62,14 @@
}
abs_mmio_write32(kBase + OTBN_START_ADDR_REG_OFFSET, start_addr);
-
- uint32_t cmd_reg_val = bitfield_bit32_write(0, OTBN_CMD_START_BIT, true);
- abs_mmio_write32(kBase + OTBN_CMD_REG_OFFSET, cmd_reg_val);
+ abs_mmio_write32(kBase + OTBN_CMD_REG_OFFSET, kOtbnCmdExecute);
return kErrorOk;
}
bool otbn_is_busy() {
uint32_t status = abs_mmio_read32(kBase + OTBN_STATUS_REG_OFFSET);
- return bitfield_bit32_read(status, OTBN_STATUS_BUSY_BIT);
+ return status != kOtbnStatusIdle;
}
void otbn_get_err_bits(otbn_err_bits_t *err_bits) {
diff --git a/sw/device/silicon_creator/lib/drivers/otbn.h b/sw/device/silicon_creator/lib/drivers/otbn.h
index 9f3c8db..0d24d49 100644
--- a/sw/device/silicon_creator/lib/drivers/otbn.h
+++ b/sw/device/silicon_creator/lib/drivers/otbn.h
@@ -26,6 +26,25 @@
extern const size_t kOtbnIMemSizeBytes;
/**
+ * OTBN commands
+ */
+typedef enum dif_otbn_cmd {
+ kOtbnCmdExecute = 0x01,
+ kOtbnCmdSecWipeDmem = 0x02,
+ kOtbnCmdSecWipeImem = 0x03,
+} otbn_cmd_t;
+
+/**
+ * OTBN status
+ */
+typedef enum otbn_status {
+ kOtbnStatusIdle = 0x00,
+ kOtbnStatusBusyExecute = 0x01,
+ kOtbnStatusBusySecWipeDmem = 0x02,
+ kOtbnStatusBusySecWipeImem = 0x03,
+} otbn_status_t;
+
+/**
* Start the execution of the application loaded into OTBN at the start address.
*
* @param start_addr The IMEM byte address to start the execution at.
diff --git a/sw/device/silicon_creator/lib/drivers/otbn_unittest.cc b/sw/device/silicon_creator/lib/drivers/otbn_unittest.cc
index 1089bf1..50da2c1 100644
--- a/sw/device/silicon_creator/lib/drivers/otbn_unittest.cc
+++ b/sw/device/silicon_creator/lib/drivers/otbn_unittest.cc
@@ -43,8 +43,8 @@
// Write start address.
EXPECT_ABS_WRITE32(base_ + OTBN_START_ADDR_REG_OFFSET, 4);
- // Set start command bit.
- EXPECT_ABS_WRITE32(base_ + OTBN_CMD_REG_OFFSET, {{OTBN_CMD_START_BIT, 1}});
+ // Set EXECUTE command.
+ EXPECT_ABS_WRITE32(base_ + OTBN_CMD_REG_OFFSET, kOtbnCmdExecute);
EXPECT_EQ(otbn_start(4), kErrorOk);
}
@@ -52,8 +52,7 @@
class IsBusyTest : public OtbnTest {};
TEST_F(IsBusyTest, Success) {
- EXPECT_ABS_READ32(base_ + OTBN_STATUS_REG_OFFSET,
- {{OTBN_STATUS_BUSY_BIT, true}});
+ EXPECT_ABS_READ32(base_ + OTBN_STATUS_REG_OFFSET, kOtbnStatusBusyExecute);
EXPECT_EQ(otbn_is_busy(), true);
}
diff --git a/sw/device/tests/dif/dif_otbn_smoketest.c b/sw/device/tests/dif/dif_otbn_smoketest.c
index f02cc52..112e6b4 100644
--- a/sw/device/tests/dif/dif_otbn_smoketest.c
+++ b/sw/device/tests/dif/dif_otbn_smoketest.c
@@ -137,7 +137,7 @@
CHECK(otbn_load_app(otbn_ctx, kAppErrTest) == kOtbnOk);
CHECK(otbn_call_function(otbn_ctx, kFuncWrapErrTest) == kOtbnOk);
- CHECK(otbn_busy_wait_for_done(otbn_ctx) == kOtbnExecutionFailed);
+ CHECK(otbn_busy_wait_for_done(otbn_ctx) == kOtbnOperationFailed);
check_otbn_err_bits(otbn_ctx, kDifOtbnErrBitsBadDataAddr);