Hugo McNally | f6298b3 | 2023-02-12 14:47:22 +0000 | [diff] [blame] | 1 | # The OpenTitan DIF Library |
Sam Elliott | 65f5613 | 2020-01-15 18:21:01 +0000 | [diff] [blame] | 2 | |
| 3 | A DIF is a "Device Interface Function". DIFs are low-level routines for |
| 4 | accessing the hardware functionality directly, and are agnostic to the |
| 5 | particular environment or context they are called from. The intention is that |
Chris Frantz | d4d5993 | 2021-04-02 08:03:58 -0700 | [diff] [blame] | 6 | DIFs are high-quality software artifacts which can be used during design |
| 7 | verification and early silicon verification. |
| 8 | |
| 9 | Although DIFs are high-quality software artifacts, they are not a hardware |
| 10 | abstraction layer (HAL), nor do they follow the device driver model of |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 11 | any particular operating system, and as such, **_DIFs are not intended |
| 12 | to be used by production firmware_**. DIFs, in combination with the |
Chris Frantz | d4d5993 | 2021-04-02 08:03:58 -0700 | [diff] [blame] | 13 | hardware specification, may be illustrative for writing drivers, but should |
| 14 | not be considered drivers themselves. |
Sam Elliott | 65f5613 | 2020-01-15 18:21:01 +0000 | [diff] [blame] | 15 | |
| 16 | This subtree provides headers and libraries known collectively as the DIF |
| 17 | libraries. |
| 18 | |
| 19 | There is one DIF library per hardware IP, and each one contains the DIFs |
| 20 | required to actuate all of the specification-required functionality of the |
Dan McArdle | 483acae | 2022-09-27 13:22:32 -0400 | [diff] [blame] | 21 | hardware they are written for. |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 22 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 23 | Each DIF library contains both auto-generated (which are checked-in to our |
| 24 | repository under the `autogen/` subtree), and manually-implemented DIFs (which |
| 25 | are not sub-foldered). |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 26 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 27 | ## Developing New DIFs |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 28 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 29 | Developers should use the `util/make_new_dif.py` script to both auto-generate a |
| 30 | subset of DIFs, *and* instantiate some initial boilerplate templates that should |
| 31 | be subsequently edited. Specifically, the script will create: |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 32 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 33 | 1. auto-generated DIF code, including: |
| 34 | * an auto-generated (private) DIF header, `autogen/dif_<ip>_autogen.h`, based |
| 35 | on `util/make_new_dif/templates/dif_autogen.h.tpl`, |
| 36 | * auto-generated DIF implementations, `autogen/dif_<ip>_autogen.c`, based on |
| 37 | `util/make_new_dif/templates/dif_autogen.c.tpl`, and |
| 38 | * auto-generated DIF unit tests (that test the auto-generated DIFs), |
| 39 | `autogen/dif_<ip>_autogen_unittest.cc`, based on |
| 40 | `util/make_new_dif/templates/dif_autogen_unittest.cc.tpl`. |
| 41 | 2. boilerplate templates (that should be manually edited/enhanced) for the |
| 42 | the portion of the IP DIF library that is manually implemented, including: |
Dan McArdle | 483acae | 2022-09-27 13:22:32 -0400 | [diff] [blame] | 43 | * a (public) header for the DIF, based on |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 44 | `util/make_new_dif/templates/dif_template.h.tpl`], and |
| 45 | * a checklist for the DIF, based on `doc/project/sw_checklist.md.tpl`. |
| 46 | |
| 47 | Only the second set of files will need checking and editing, but the templates |
| 48 | serve to avoid most of the copy/paste required, while keeping our DIF libraries |
| 49 | consistent across IPs. |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 50 | |
| 51 | Further documentation for the script is provided in the script's source. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 52 | Additionally, please invoke `util/make_new_dif.py --help` for detailed usage. |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 53 | |
Sam Elliott | a939181 | 2020-06-05 11:21:15 +0100 | [diff] [blame] | 54 | ## Checklists |
| 55 | |
| 56 | This directory also contains checklists for each DIF, in markdown format. They |
Hugo McNally | aef0a66 | 2023-02-11 19:44:55 +0000 | [diff] [blame] | 57 | are linked to from the [Hardware Dashboard](../../../../hw/README.md), in the |
Sam Elliott | a939181 | 2020-06-05 11:21:15 +0100 | [diff] [blame] | 58 | Development Stage column. |
| 59 | |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 60 | ## DIF Style Guide |
| 61 | |
| 62 | DIFs are very low-level software, so they have a more rigorous coding style than |
| 63 | other parts of the codebase. |
| 64 | |
| 65 | DIFs should follow the [OpenTitan C/C++ style |
| 66 | guide](https://docs.opentitan.org/doc/rm/c_cpp_coding_style/) where it does not |
| 67 | contradict with the guidelines below. |
| 68 | |
| 69 | The guidelines below apply to writing DIFs, and code should be written in a |
| 70 | similar style to the existing DIF libraries in this directory. |
| 71 | |
Sam Elliott | 9a5da26 | 2020-06-05 12:02:52 +0100 | [diff] [blame] | 72 | ### Definitions |
| 73 | |
| 74 | <a name="side-effects"></a> |
| 75 | **Side-effects** include (but are not limited to) writing to memory, including |
| 76 | memory-mapped hardware, and modifying processor CSRs. |
| 77 | |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 78 | ### DIF Library Guidance |
| 79 | |
| 80 | * DIF libraries must be written in C. |
| 81 | * DIF libraries can only depend on the following headers (and their associated |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 82 | libraries): |
Sam Elliott | 8b47be3 | 2020-05-12 18:20:49 +0100 | [diff] [blame] | 83 | * `sw/device/lib/base/bitfield.h` |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 84 | * `sw/device/lib/base/mmio.h` |
| 85 | * `sw/device/lib/base/memory.h` |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 86 | * `sw/device/lib/dif/dif_base.h` |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 87 | * DIF libraries must not depend on other DIF libraries. Exercising DIF |
| 88 | functionality may require an environment set up using another DIF library, but |
| 89 | DIFs must not call DIFs in other DIF libraries. |
Sam Elliott | 113040c | 2020-06-05 11:41:42 +0100 | [diff] [blame] | 90 | * DIF library headers must be polyglot headers for C and C++. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 91 | * the public (manually-implemented) DIF header for each DIF library should |
| 92 | `#include` the (private) auto-generated header, so that DIF consumers need |
| 93 | only `#include` the public DIF header to make use of an IP's DIF library. |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 94 | |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 95 | ### DIF API Guidance |
| 96 | |
| 97 | The following rules specify the basic API that each DIF must conform to. These |
| 98 | rules specify the names of types, constants, and functions that each DIF must |
| 99 | define for providing certain kinds of non-device-specific functionality (such as |
| 100 | initializing handles or managing interrupts). |
| 101 | |
| 102 | Notational caveats: |
| 103 | * The token `<ip>` is the "short IP name" of the peripheral, |
| 104 | in `snake_case` or `PascalCase` as is appropriate. |
| 105 | * The parameter name `handle` is not normative, and DIF libraries are free to |
| 106 | choose a different, but consistent, name for it. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 107 | * All functions below are assumed to return `dif_result_t`, a global DIF return |
| 108 | type defined in `sw/device/lib/dif/dif_base.h`. |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 109 | * Unless otherwise noted, all symbols mentioned below are required. |
| 110 | |
Sam Elliott | 7d25fd9 | 2020-11-06 12:05:06 +0000 | [diff] [blame] | 111 | #### Hardware Parameterization |
| 112 | |
| 113 | Our aim is that a single DIF library can be used with multiple instances of the |
| 114 | same IP on the same chip, even when those IPs have been instantiated with |
| 115 | different hardware parameters. |
| 116 | |
| 117 | At the moment, we have a good approach to being able to address separate |
| 118 | hardware instances instantiated at separate addresses, as long as they have the |
Timothy Trippel | af6cbf0 | 2021-10-15 00:41:26 +0000 | [diff] [blame] | 119 | same hardware parameters (see the `base_addr` member in `dif_<ip>_t`). |
| 120 | Most other parameters come from the specific IP on a case-by-case basis, and are |
| 121 | extracted from the IP's auto-generated register header file, e.g., |
| 122 | `<ip>_regs.h`. |
Sam Elliott | 7d25fd9 | 2020-11-06 12:05:06 +0000 | [diff] [blame] | 123 | |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 124 | #### Base Types |
| 125 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 126 | There are two categories of base types: |
| 127 | 1. those that are defined once in `sw/device/lib/dif/dif_base.h` and used in all |
| 128 | DIF libraries, and |
| 129 | 2. those that are expected to be defined separately by all DIF libraries (unless |
| 130 | otherwise specified). |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 131 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 132 | The base types defined in `sw/device/lib/dif/dif_base.h` include: |
| 133 | * `dif_result_t` -- an enum representing global DIF return codes. |
| 134 | * `dif_toggle_t` -- an enum to be used instead of a `bool` when describing |
| 135 | enablement states. |
| 136 | |
| 137 | The base types that are expected to be defined separately by all DIF libraries |
| 138 | include: |
Dan McArdle | 483acae | 2022-09-27 13:22:32 -0400 | [diff] [blame] | 139 | * `dif_<ip>_t` -- an **auto-generated** type representing a handle to the |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 140 | peripheral. Its first (and only) field is always the base address for the |
| 141 | peripheral registers, styled `mmio_region_t base_addr;`. |
| 142 | This type is usually passed by `const` pointer, except when it is |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 143 | being initialized (see `dif_<ip>_init()` below). |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 144 | * `dif_<ip>_config_t` -- a **manually-defined** struct representing runtime |
| 145 | configuration parameters for the peripheral. It is only present when |
| 146 | `dif_<ip>_configure()` is defined. This type is always passed by value. |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 147 | |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 148 | #### Lifecycle Functions |
| 149 | The following functions are the basic functionality for initializing and |
| 150 | handling the lifetime of a handle. |
| 151 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 152 | * `dif_result_t dif_<ip>_init(mmio_region_t base_addr, dif_<ip>_t *handle);` |
| 153 | initializes `handle` with with the base address of the instantiated IP this |
| 154 | DIF is targeting to use. This DIF is **auto-generated**. |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 155 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 156 | * `dif_result_t dif_<ip>_configure(const dif_<ip>_t *handle, dif_<ip>_config_t |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 157 | config);` configures the hardware managed by `handle` with runtime parameters |
| 158 | in an implementation-defined way. This function should be "one-off": it should |
| 159 | only need to be called once for the lifetime of the handle. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 160 | _If there is no meaningful state to configure, this function may be omitted._ |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 161 | In particular, DIF libraries providing transaction functions will usually have |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 162 | no need for this function at all. This DIF is **manually-implemented**. |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 163 | |
| 164 | #### Transaction Management |
| 165 | |
| 166 | The following types and functions are the standard interface for |
| 167 | *transaction-oriented* peripherals, in which a client schedules an operation to |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 168 | be completed at some point in the future. All types and functions listed here |
| 169 | are **manually-implemented**. |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 170 | |
| 171 | * `dif_<ip>_transaction_t` is a struct representing runtime parameters for |
| 172 | starting a hardware transaction. It is only present when `dif_<ip>_start()` is |
| 173 | defined. This type is always passed by value. A DIF library my opt to use |
Dan McArdle | 468992e | 2022-09-27 12:51:18 -0400 | [diff] [blame] | 174 | another pre-existing type instead, when that type provides a more semantically |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 175 | appropriate meaning. |
| 176 | * `dif_<ip>_output_t` is a struct describing how to output a completed |
| 177 | transaction. Often, this will be a type like `uint8_t *`. The same caveats |
| 178 | about a DIF library providing a different type apply here. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 179 | * `dif_result_t dif_<ip>_start(const dif_<ip>_t *handle, dif_<ip>_transaction_t |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 180 | transaction);` starts a transaction on a transaction-oriented peripheral. This |
| 181 | function may be called multiple times, but each call should be paired with a |
| 182 | `dif_<ip>_end()` call. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 183 | * `dif_result_t dif_<ip>_end(const dif_<ip>_t *handle, dif_<ip>_output_t out);` |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 184 | completes a transaction started with `dif_<ip>_start()`, writing its results |
| 185 | to a location specified in `out`. |
| 186 | |
| 187 | If a peripheral supports multiple transaction modes with incompatible parameter |
| 188 | types, the above names may be duplicated by inserting `mode_<mode>` after `<ip>`. |
| 189 | For example, |
| 190 | ``` |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 191 | dif_result_t dif_<ip>_mode_<mode>_end(const dif_<ip>_t *handle, |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 192 | dif_<ip>_mode_<mode>_output_t out); |
| 193 | ``` |
| 194 | There is no requirement that `_start()` and `_end()` share the same set of |
| 195 | `<mode>`s; for example, there might be a single `dif_<ip>_start()` but many |
Dan McArdle | 468992e | 2022-09-27 12:51:18 -0400 | [diff] [blame] | 196 | `dif_<ip>_mode_<mode>_end()`s. This style of API is preferred over using |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 197 | `union`s with `dif_<ip>_transaction_t` and `dif_<ip>_output_t`. |
| 198 | |
| 199 | #### Register Locking |
| 200 | |
| 201 | The following functions are the standard interface for peripherals that can lock |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 202 | portions of their software-accessible functionality. All types and functions |
| 203 | listed here are **manually-implemented**. |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 204 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 205 | * `kDifLocked` is the global return result enum of an operation that can be |
| 206 | locked out. DIFs which may fail due to lockout, which is software-detectable, |
| 207 | should return this value when possible. |
| 208 | * `dif_result_t dif_<ip>_lock(const dif_<ip>_t *handle);` locks out all portions |
| 209 | of the peripheral which can be locked. If a peripheral can be locked-out |
| 210 | piecewise, `dif_<ip>_lock_<operation>()` functions may be provided alongside |
| 211 | or in lieu of `dif_<ip>_lock()`. |
| 212 | * `dif_result_t dif_<ip>_is_locked(const dif_<ip>_t *handle, bool *is_locked);` |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 213 | checks whether the peripheral has been locked out. As with `dif_<ip>_lock()`, |
| 214 | DIF libraries may provide a piecewise version of this API. |
| 215 | |
| 216 | #### Interrupt Management |
| 217 | |
| 218 | The following types and functions are the standard interface for peripherals that |
| 219 | provide a collection of `INTR_ENABLE`, `INTR_STATE`, and `INTR_TEST` registers |
| 220 | for interrupt management. A DIF library for a peripheral providing such |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 221 | registers must provide this interface. To ensure this, all interrupt DIFs, |
| 222 | including: headers, (C) implementations, and unit tests, are *auto-generated* from |
| 223 | templates and an IP's HJSON configuration file using the `util/make_new_dif.py` |
Dan McArdle | 468992e | 2022-09-27 12:51:18 -0400 | [diff] [blame] | 224 | tool (described above). |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 225 | |
| 226 | If a peripheral is defined with `no_auto_intr_regs: true`, this exact API is not |
| 227 | required even if the `INTR_` registers are provided (though DIF libraries are |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 228 | encouraged to follow it where it makes sense). _In these cases, auto-generated |
| 229 | interrupt DIFs may not exist._ |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 230 | |
| 231 | * `dif_<ip>_irq_t` is an enum that lists all of the interrupt types for this |
Dan McArdle | 468992e | 2022-09-27 12:51:18 -0400 | [diff] [blame] | 232 | peripheral. These derived from the `interrupt_list` attribute within an IP's |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 233 | HJSON file. |
Dan McArdle | 483acae | 2022-09-27 13:22:32 -0400 | [diff] [blame] | 234 | * `dif_result_t dif_<ip>_irq_get_state(const dif_<ip>_t *handle, |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 235 | dif_<ip>_irq_state_snapshot_t *snapshot, bool *is_pending);` returns a |
| 236 | snapshot of the entire interrupt state register, to check the status of all |
Dan McArdle | 483acae | 2022-09-27 13:22:32 -0400 | [diff] [blame] | 237 | interrupts for a peripheral. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 238 | * `dif_result_t dif_<ip>_irq_is_pending(const dif_<ip>_t *handle, dif_<ip>_irq_t |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 239 | irq, bool *is_pending);` checks whether a specific interrupt is |
| 240 | pending (i.e., if the interrupt has been asserted but not yet cleared). |
Dan McArdle | 483acae | 2022-09-27 13:22:32 -0400 | [diff] [blame] | 241 | * `dif_result_t dif_<ip>_irq_acknowledge_all(const dif_<ip>_t *handle);` |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 242 | acknowledges all interrupts have been serviced, marking them as |
| 243 | complete by clearing all pending bits. This function does nothing and returns |
| 244 | `kDifOk` if no interrupts were pending. |
| 245 | * `dif_result_t dif_<ip>_irq_acknowledge(const dif_<ip>_t *handle, dif_<ip>_irq_t |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 246 | irq);` acknowledges that an interrupt has been serviced, marking it as |
| 247 | complete by clearing its pending bit. This function does nothing and returns |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 248 | `kDifOk` if the interrupt wasn't pending. |
| 249 | * `dif_result_t dif_<ip>_irq_get_enabled(const dif_<ip>_t *handle, dif_<ip>_irq_t |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 250 | irq, const dif_<ip>_toggle_t *state);` gets whether an interrupt is |
| 251 | enabled (i.e., masked). |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 252 | * `dif_result_t dif_<ip>_irq_set_enabled(const dif_<ip>_t *handle, dif_<ip>_irq_t |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 253 | irq, dif_<ip>_toggle_t state);` sets whether a particular interrupt is |
| 254 | enabled (i.e., masked). |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 255 | * `dif_result_t dif_<ip>_irq_force(const dif_<ip>_t *handle, dif_<ip>_irq_t |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 256 | irq);` forcibly asserts a specific interrupt, causing it to be serviced |
| 257 | as if hardware had triggered it. |
| 258 | |
| 259 | Additionally, the following types allow for batch save/restore operations on |
| 260 | the interrupt enable register: |
| 261 | |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 262 | * `dif_<ip>_irq_enable_snapshot_t` is a type that encapsulates restorable |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 263 | interrupt enablement state, to be used with the two functions below. This type |
| 264 | should be treated as opaque by clients. |
| 265 | * `dif_result_t dif_<ip>_irq_disable_all(const dif_<ip>_t *handle, |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 266 | dif_<ip>_irq_enable_snapshot_t *snapshot);` disables all interrupts associated |
| 267 | with the peripheral, saving them to `*snapshot`. `snapshot` may be null, in |
| 268 | which case the previous enablement state is not saved. |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 269 | * `dif_result_t dif_<ip>_irq_restore_all(const dif_<ip>_t *handle, |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 270 | const dif_<ip>_irq_enable_snapshot_t *snapshot);` restores an interrupt |
| 271 | enablement snapshot produced by the above function. |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 272 | |
| 273 | #### Unit Testing |
| 274 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 275 | Each DIF has an associated unit test, written in C++. For auto-generated DIFs, |
| 276 | their associated unit tests are also auto-generated. For manually-implemented |
| 277 | DIFs, their associated unit tests follow the conventions: |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 278 | * The whole file is wrapped in the `dif_<ip>_unittest` namespace. |
| 279 | * There is a base class for all test fixtures, named `<ip>Test`, which derives |
| 280 | `testing::Test` and `mock_mmio::MmioTest`. |
| 281 | * Each function has an associated test fixture, usually named |
| 282 | `<function>Test`, which derives `<ip>Test`. Multiple similar functions may be |
| 283 | grouped under one fixture. |
Miguel Young de la Sota | b6fa220 | 2022-03-14 13:36:51 -0400 | [diff] [blame] | 284 | * Prefer to use expectation macros, like `EXPECT_DIF_OK`, defined in |
| 285 | `dif_test_base.h` whenever possible (e.g. do not write |
| 286 | `EXPECT_EQ(<long expression>, kDifOk);`). |
Miguel Young de la Sota | 74fd7ce | 2020-08-18 16:32:17 -0400 | [diff] [blame] | 287 | |
| 288 | ### DIF Style Guidance |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 289 | |
| 290 | The following rules must be followed by public DIF functions (those declared in |
| 291 | the DIF library's header file). Internal DIF functions (those declared `static` |
| 292 | and not declared in the DIF library's header file) should follow these rules but |
| 293 | there are some relaxations of these rules for them described at the end. |
| 294 | |
| 295 | * DIF declarations must match their definitions exactly. |
| 296 | * Scalar arguments must not be declared `const` or `volatile` (cv-qualified) |
| 297 | in DIF signatures. |
| 298 | |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 299 | * DIFs must use one of the `dif_result_t` enums (described in |
| 300 | `sw/device/lib/dif/dif_base.h`) rather than booleans for reporting errors. If |
| 301 | a DIF can either error or instead produce a value, it must return a |
| 302 | `dif_result_t`, and use an out-parameter for returning the produced value. |
Miguel Young de la Sota | 244cceb | 2020-06-23 13:28:40 -0400 | [diff] [blame] | 303 | * DIFs that return an enum return code must be annotated with |
Miguel Young de la Sota | ef7251a | 2022-03-16 14:58:37 -0400 | [diff] [blame] | 304 | `OT_WARN_UNUSED_RESULT`, to help minimize mistakes from |
Miguel Young de la Sota | 244cceb | 2020-06-23 13:28:40 -0400 | [diff] [blame] | 305 | failing to check a result. This guidance applies to `static` helper |
| 306 | functions that return an error of some kind as well. |
Sam Elliott | 8aa5079 | 2020-05-12 18:22:28 +0100 | [diff] [blame] | 307 | * DIFs that cannot error and that do not return a value must return `void`. |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 308 | |
| 309 | * DIFs must check their arguments against preconditions using "guard |
| 310 | statements". A guard statement is a simple if statement at the start of a |
| 311 | function which only returns an error code if the preconditions are not met. |
| 312 | Guard statements must cover the following checks: |
| 313 | * DIFs must ensure their pointer arguments are non-null, unless that pointer |
| 314 | is for an optional out-parameter. Arguments typed `mmio_region_t` are not |
| 315 | pointers, and cannot meaningfully be checked for non-nullness. |
| 316 | * DIFs must ensure, if they only accept a subset of an enum, that the argument |
Sam Elliott | 50296b9 | 2020-06-05 11:44:34 +0100 | [diff] [blame] | 317 | is within that subset. However, DIFs may assume, for checking preconditions, |
| 318 | that any enum argument is one of the enum constants. |
Sam Elliott | 9a5da26 | 2020-06-05 12:02:52 +0100 | [diff] [blame] | 319 | * DIFs must not cause any side-effects before any guard statements. This means |
| 320 | returning early from a guard statement must not leave the hardware in an |
| 321 | invalid or unrecoverable state. |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 322 | |
| 323 | * Switch statements in DIFs must always have a default case, including when |
| 324 | switching on an enum value (an "enum switch"). |
| 325 | * The default case of an enum switch must report an error for values that are |
Sam Elliott | 8aa5079 | 2020-05-12 18:22:28 +0100 | [diff] [blame] | 326 | not a constant from that enum. In the absence of more specific information, |
Timothy Trippel | 3d156ce | 2021-11-03 03:11:04 +0000 | [diff] [blame] | 327 | this should return `kDifError` or the equivalent return code value from |
| 328 | a global DIF return code enum. If the enum switch is part of a guard |
| 329 | statement, it may return `kDifBadArg` instead. |
Sam Elliott | 8aa5079 | 2020-05-12 18:22:28 +0100 | [diff] [blame] | 330 | * Enum switches do not need a `case` for enum constants that are unreachable |
Sam Elliott | 3561cc5 | 2020-02-07 14:12:28 +0000 | [diff] [blame] | 331 | due to a guard statement. |
| 332 | |
| 333 | * DIFs must use `sw/device/lib/base/mmio.h` for accessing memory-mapped |
| 334 | hardware. DIFs must not use `sw/device/lib/base/memory.h` for accessing |
| 335 | memory-mapped hardware. |
| 336 | |
| 337 | * Internal DIF functions, which are not intended to be part of a public DIF |
| 338 | library interface, must not be declared in the DIF library header, and must be |
| 339 | marked `static`. |
| 340 | * `static` DIF functions should not be marked `static inline`. |
| 341 | * An internal DIF function does not need to check preconditions, if all the |
| 342 | DIF functions that call it have already checked that precondition. |