blob: e34067755a23cdd09ed0652e8169a344f82c06b9 [file] [log] [blame] [view]
Hugo McNallyf6298b32023-02-12 14:47:22 +00001# The OpenTitan DIF Library
Sam Elliott65f56132020-01-15 18:21:01 +00002
3A DIF is a "Device Interface Function". DIFs are low-level routines for
4accessing the hardware functionality directly, and are agnostic to the
5particular environment or context they are called from. The intention is that
Chris Frantzd4d59932021-04-02 08:03:58 -07006DIFs are high-quality software artifacts which can be used during design
7verification and early silicon verification.
8
9Although DIFs are high-quality software artifacts, they are not a hardware
10abstraction layer (HAL), nor do they follow the device driver model of
Timothy Trippel3d156ce2021-11-03 03:11:04 +000011any particular operating system, and as such, **_DIFs are not intended
12to be used by production firmware_**. DIFs, in combination with the
Chris Frantzd4d59932021-04-02 08:03:58 -070013hardware specification, may be illustrative for writing drivers, but should
14not be considered drivers themselves.
Sam Elliott65f56132020-01-15 18:21:01 +000015
16This subtree provides headers and libraries known collectively as the DIF
17libraries.
18
19There is one DIF library per hardware IP, and each one contains the DIFs
20required to actuate all of the specification-required functionality of the
Dan McArdle483acae2022-09-27 13:22:32 -040021hardware they are written for.
Sam Elliott3561cc52020-02-07 14:12:28 +000022
Timothy Trippel3d156ce2021-11-03 03:11:04 +000023Each DIF library contains both auto-generated (which are checked-in to our
24repository under the `autogen/` subtree), and manually-implemented DIFs (which
25are not sub-foldered).
Sam Elliottf18219f2020-09-23 17:46:10 +010026
Timothy Trippel3d156ce2021-11-03 03:11:04 +000027## Developing New DIFs
Sam Elliottf18219f2020-09-23 17:46:10 +010028
Timothy Trippel3d156ce2021-11-03 03:11:04 +000029Developers should use the `util/make_new_dif.py` script to both auto-generate a
30subset of DIFs, *and* instantiate some initial boilerplate templates that should
31be subsequently edited. Specifically, the script will create:
Sam Elliottf18219f2020-09-23 17:46:10 +010032
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000331. 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`.
412. boilerplate templates (that should be manually edited/enhanced) for the
42 the portion of the IP DIF library that is manually implemented, including:
Dan McArdle483acae2022-09-27 13:22:32 -040043 * a (public) header for the DIF, based on
Timothy Trippel3d156ce2021-11-03 03:11:04 +000044 `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
47Only the second set of files will need checking and editing, but the templates
48serve to avoid most of the copy/paste required, while keeping our DIF libraries
49consistent across IPs.
Sam Elliottf18219f2020-09-23 17:46:10 +010050
51Further documentation for the script is provided in the script's source.
Timothy Trippel3d156ce2021-11-03 03:11:04 +000052Additionally, please invoke `util/make_new_dif.py --help` for detailed usage.
Sam Elliottf18219f2020-09-23 17:46:10 +010053
Sam Elliotta9391812020-06-05 11:21:15 +010054## Checklists
55
56This directory also contains checklists for each DIF, in markdown format. They
Hugo McNallyaef0a662023-02-11 19:44:55 +000057are linked to from the [Hardware Dashboard](../../../../hw/README.md), in the
Sam Elliotta9391812020-06-05 11:21:15 +010058Development Stage column.
59
Sam Elliott3561cc52020-02-07 14:12:28 +000060## DIF Style Guide
61
62DIFs are very low-level software, so they have a more rigorous coding style than
63other parts of the codebase.
64
65DIFs should follow the [OpenTitan C/C++ style
66guide](https://docs.opentitan.org/doc/rm/c_cpp_coding_style/) where it does not
67contradict with the guidelines below.
68
69The guidelines below apply to writing DIFs, and code should be written in a
70similar style to the existing DIF libraries in this directory.
71
Sam Elliott9a5da262020-06-05 12:02:52 +010072### Definitions
73
74<a name="side-effects"></a>
75**Side-effects** include (but are not limited to) writing to memory, including
76memory-mapped hardware, and modifying processor CSRs.
77
Sam Elliott3561cc52020-02-07 14:12:28 +000078### 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 Trippel3d156ce2021-11-03 03:11:04 +000082 libraries):
Sam Elliott8b47be32020-05-12 18:20:49 +010083 * `sw/device/lib/base/bitfield.h`
Sam Elliott3561cc52020-02-07 14:12:28 +000084 * `sw/device/lib/base/mmio.h`
85 * `sw/device/lib/base/memory.h`
Timothy Trippel3d156ce2021-11-03 03:11:04 +000086 * `sw/device/lib/dif/dif_base.h`
Sam Elliott3561cc52020-02-07 14:12:28 +000087* 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 Elliott113040c2020-06-05 11:41:42 +010090* DIF library headers must be polyglot headers for C and C++.
Timothy Trippel3d156ce2021-11-03 03:11:04 +000091* 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 Elliott3561cc52020-02-07 14:12:28 +000094
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -040095### DIF API Guidance
96
97The following rules specify the basic API that each DIF must conform to. These
98rules specify the names of types, constants, and functions that each DIF must
99define for providing certain kinds of non-device-specific functionality (such as
100initializing handles or managing interrupts).
101
102Notational 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 Trippel3d156ce2021-11-03 03:11:04 +0000107* 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 Sota74fd7ce2020-08-18 16:32:17 -0400109* Unless otherwise noted, all symbols mentioned below are required.
110
Sam Elliott7d25fd92020-11-06 12:05:06 +0000111#### Hardware Parameterization
112
113Our aim is that a single DIF library can be used with multiple instances of the
114same IP on the same chip, even when those IPs have been instantiated with
115different hardware parameters.
116
117At the moment, we have a good approach to being able to address separate
118hardware instances instantiated at separate addresses, as long as they have the
Timothy Trippelaf6cbf02021-10-15 00:41:26 +0000119same hardware parameters (see the `base_addr` member in `dif_<ip>_t`).
120Most other parameters come from the specific IP on a case-by-case basis, and are
121extracted from the IP's auto-generated register header file, e.g.,
122`<ip>_regs.h`.
Sam Elliott7d25fd92020-11-06 12:05:06 +0000123
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400124#### Base Types
125
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000126There are two categories of base types:
1271. those that are defined once in `sw/device/lib/dif/dif_base.h` and used in all
128 DIF libraries, and
1292. those that are expected to be defined separately by all DIF libraries (unless
130 otherwise specified).
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400131
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000132The 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
137The base types that are expected to be defined separately by all DIF libraries
138include:
Dan McArdle483acae2022-09-27 13:22:32 -0400139* `dif_<ip>_t` -- an **auto-generated** type representing a handle to the
Timothy Trippelce9232e2021-09-13 22:48:18 +0000140 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 Sota74fd7ce2020-08-18 16:32:17 -0400143 being initialized (see `dif_<ip>_init()` below).
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000144* `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 Sota74fd7ce2020-08-18 16:32:17 -0400147
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400148#### Lifecycle Functions
149The following functions are the basic functionality for initializing and
150handling the lifetime of a handle.
151
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000152* `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 Trippelce9232e2021-09-13 22:48:18 +0000155
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000156* `dif_result_t dif_<ip>_configure(const dif_<ip>_t *handle, dif_<ip>_config_t
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400157 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 Trippel3d156ce2021-11-03 03:11:04 +0000160 _If there is no meaningful state to configure, this function may be omitted._
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400161 In particular, DIF libraries providing transaction functions will usually have
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000162 no need for this function at all. This DIF is **manually-implemented**.
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400163
164#### Transaction Management
165
166The following types and functions are the standard interface for
167*transaction-oriented* peripherals, in which a client schedules an operation to
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000168be completed at some point in the future. All types and functions listed here
169are **manually-implemented**.
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400170
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 McArdle468992e2022-09-27 12:51:18 -0400174 another pre-existing type instead, when that type provides a more semantically
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400175 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 Trippel3d156ce2021-11-03 03:11:04 +0000179* `dif_result_t dif_<ip>_start(const dif_<ip>_t *handle, dif_<ip>_transaction_t
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400180 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 Trippel3d156ce2021-11-03 03:11:04 +0000183* `dif_result_t dif_<ip>_end(const dif_<ip>_t *handle, dif_<ip>_output_t out);`
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400184 completes a transaction started with `dif_<ip>_start()`, writing its results
185 to a location specified in `out`.
186
187If a peripheral supports multiple transaction modes with incompatible parameter
188types, the above names may be duplicated by inserting `mode_<mode>` after `<ip>`.
189For example,
190```
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000191dif_result_t dif_<ip>_mode_<mode>_end(const dif_<ip>_t *handle,
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400192 dif_<ip>_mode_<mode>_output_t out);
193```
194There 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 McArdle468992e2022-09-27 12:51:18 -0400196`dif_<ip>_mode_<mode>_end()`s. This style of API is preferred over using
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400197`union`s with `dif_<ip>_transaction_t` and `dif_<ip>_output_t`.
198
199#### Register Locking
200
201The following functions are the standard interface for peripherals that can lock
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000202portions of their software-accessible functionality. All types and functions
203listed here are **manually-implemented**.
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400204
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000205* `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 Sota74fd7ce2020-08-18 16:32:17 -0400213 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
218The following types and functions are the standard interface for peripherals that
219provide a collection of `INTR_ENABLE`, `INTR_STATE`, and `INTR_TEST` registers
220for interrupt management. A DIF library for a peripheral providing such
Timothy Trippelce9232e2021-09-13 22:48:18 +0000221registers must provide this interface. To ensure this, all interrupt DIFs,
222including: headers, (C) implementations, and unit tests, are *auto-generated* from
223templates and an IP's HJSON configuration file using the `util/make_new_dif.py`
Dan McArdle468992e2022-09-27 12:51:18 -0400224tool (described above).
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400225
226If a peripheral is defined with `no_auto_intr_regs: true`, this exact API is not
227required even if the `INTR_` registers are provided (though DIF libraries are
Timothy Trippelce9232e2021-09-13 22:48:18 +0000228encouraged to follow it where it makes sense). _In these cases, auto-generated
229interrupt DIFs may not exist._
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400230
231* `dif_<ip>_irq_t` is an enum that lists all of the interrupt types for this
Dan McArdle468992e2022-09-27 12:51:18 -0400232 peripheral. These derived from the `interrupt_list` attribute within an IP's
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000233 HJSON file.
Dan McArdle483acae2022-09-27 13:22:32 -0400234* `dif_result_t dif_<ip>_irq_get_state(const dif_<ip>_t *handle,
Timothy Trippelce9232e2021-09-13 22:48:18 +0000235 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 McArdle483acae2022-09-27 13:22:32 -0400237 interrupts for a peripheral.
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000238* `dif_result_t dif_<ip>_irq_is_pending(const dif_<ip>_t *handle, dif_<ip>_irq_t
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400239 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 McArdle483acae2022-09-27 13:22:32 -0400241* `dif_result_t dif_<ip>_irq_acknowledge_all(const dif_<ip>_t *handle);`
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000242 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 Sota74fd7ce2020-08-18 16:32:17 -0400246 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 Trippel3d156ce2021-11-03 03:11:04 +0000248 `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 Sota74fd7ce2020-08-18 16:32:17 -0400250 irq, const dif_<ip>_toggle_t *state);` gets whether an interrupt is
251 enabled (i.e., masked).
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000252* `dif_result_t dif_<ip>_irq_set_enabled(const dif_<ip>_t *handle, dif_<ip>_irq_t
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400253 irq, dif_<ip>_toggle_t state);` sets whether a particular interrupt is
254 enabled (i.e., masked).
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000255* `dif_result_t dif_<ip>_irq_force(const dif_<ip>_t *handle, dif_<ip>_irq_t
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400256 irq);` forcibly asserts a specific interrupt, causing it to be serviced
257 as if hardware had triggered it.
258
259Additionally, the following types allow for batch save/restore operations on
260the interrupt enable register:
261
Timothy Trippelce9232e2021-09-13 22:48:18 +0000262* `dif_<ip>_irq_enable_snapshot_t` is a type that encapsulates restorable
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000263 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 Trippelce9232e2021-09-13 22:48:18 +0000266 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 Trippel3d156ce2021-11-03 03:11:04 +0000269* `dif_result_t dif_<ip>_irq_restore_all(const dif_<ip>_t *handle,
Timothy Trippelce9232e2021-09-13 22:48:18 +0000270 const dif_<ip>_irq_enable_snapshot_t *snapshot);` restores an interrupt
271 enablement snapshot produced by the above function.
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400272
273#### Unit Testing
274
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000275Each DIF has an associated unit test, written in C++. For auto-generated DIFs,
276their associated unit tests are also auto-generated. For manually-implemented
277DIFs, their associated unit tests follow the conventions:
Miguel Young de la Sota74fd7ce2020-08-18 16:32:17 -0400278* 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 Sotab6fa2202022-03-14 13:36:51 -0400284* 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 Sota74fd7ce2020-08-18 16:32:17 -0400287
288### DIF Style Guidance
Sam Elliott3561cc52020-02-07 14:12:28 +0000289
290The following rules must be followed by public DIF functions (those declared in
291the DIF library's header file). Internal DIF functions (those declared `static`
292and not declared in the DIF library's header file) should follow these rules but
293there 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 Trippel3d156ce2021-11-03 03:11:04 +0000299* 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 Sota244cceb2020-06-23 13:28:40 -0400303 * DIFs that return an enum return code must be annotated with
Miguel Young de la Sotaef7251a2022-03-16 14:58:37 -0400304 `OT_WARN_UNUSED_RESULT`, to help minimize mistakes from
Miguel Young de la Sota244cceb2020-06-23 13:28:40 -0400305 failing to check a result. This guidance applies to `static` helper
306 functions that return an error of some kind as well.
Sam Elliott8aa50792020-05-12 18:22:28 +0100307 * DIFs that cannot error and that do not return a value must return `void`.
Sam Elliott3561cc52020-02-07 14:12:28 +0000308
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 Elliott50296b92020-06-05 11:44:34 +0100317 is within that subset. However, DIFs may assume, for checking preconditions,
318 that any enum argument is one of the enum constants.
Sam Elliott9a5da262020-06-05 12:02:52 +0100319 * 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 Elliott3561cc52020-02-07 14:12:28 +0000322
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 Elliott8aa50792020-05-12 18:22:28 +0100326 not a constant from that enum. In the absence of more specific information,
Timothy Trippel3d156ce2021-11-03 03:11:04 +0000327 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 Elliott8aa50792020-05-12 18:22:28 +0100330 * Enum switches do not need a `case` for enum constants that are unreachable
Sam Elliott3561cc52020-02-07 14:12:28 +0000331 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.