| # The OpenTitan DIF Library | 
 |  | 
 | A DIF is a "Device Interface Function". DIFs are low-level routines for | 
 | accessing the hardware functionality directly, and are agnostic to the | 
 | particular environment or context they are called from. The intention is that | 
 | DIFs are high-quality software artifacts which can be used during design | 
 | verification and early silicon verification. | 
 |  | 
 | Although DIFs are high-quality software artifacts, they are not a hardware | 
 | abstraction layer (HAL), nor do they follow the device driver model of | 
 | any particular operating system, and as such, **_DIFs are not intended | 
 | to be used by production firmware_**.  DIFs, in combination with the | 
 | hardware specification, may be illustrative for writing drivers, but should | 
 | not be considered drivers themselves. | 
 |  | 
 | This subtree provides headers and libraries known collectively as the DIF | 
 | libraries. | 
 |  | 
 | There is one DIF library per hardware IP, and each one contains the DIFs | 
 | required to actuate all of the specification-required functionality of the | 
 | hardware they are written for. | 
 |  | 
 | Each DIF library contains both auto-generated (which are checked-in to our | 
 | repository under the `autogen/` subtree), and manually-implemented DIFs (which | 
 | are not sub-foldered). | 
 |  | 
 | ## Developing New DIFs | 
 |  | 
 | Developers should use the `util/make_new_dif.py` script to both auto-generate a | 
 | subset of DIFs, *and* instantiate some initial boilerplate templates that should | 
 | be subsequently edited. Specifically, the script will create: | 
 |  | 
 | 1. auto-generated DIF code, including: | 
 |   * an auto-generated (private) DIF header, `autogen/dif_<ip>_autogen.h`, based | 
 |   on `util/make_new_dif/templates/dif_autogen.h.tpl`, | 
 |   * auto-generated DIF implementations, `autogen/dif_<ip>_autogen.c`, based on | 
 |   `util/make_new_dif/templates/dif_autogen.c.tpl`, and | 
 |   * auto-generated DIF unit tests (that test the auto-generated DIFs), | 
 |   `autogen/dif_<ip>_autogen_unittest.cc`, based on | 
 |   `util/make_new_dif/templates/dif_autogen_unittest.cc.tpl`. | 
 | 2. boilerplate templates (that should be manually edited/enhanced) for the | 
 |    the portion of the IP DIF library that is manually implemented, including: | 
 |   * a (public) header for the DIF, based on | 
 |   `util/make_new_dif/templates/dif_template.h.tpl`], and | 
 |   * a checklist for the DIF, based on `doc/project/sw_checklist.md.tpl`. | 
 |  | 
 | Only the second set of files will need checking and editing, but the templates | 
 | serve to avoid most of the copy/paste required, while keeping our DIF libraries | 
 | consistent across IPs. | 
 |  | 
 | Further documentation for the script is provided in the script's source. | 
 | Additionally, please invoke `util/make_new_dif.py --help` for detailed usage. | 
 |  | 
 | ## Checklists | 
 |  | 
 | This directory also contains checklists for each DIF, in markdown format. They | 
 | are linked to from the [Hardware Dashboard](../../../../hw/README.md), in the | 
 | Development Stage column. | 
 |  | 
 | ## DIF Style Guide | 
 |  | 
 | DIFs are very low-level software, so they have a more rigorous coding style than | 
 | other parts of the codebase. | 
 |  | 
 | DIFs should follow the [OpenTitan C/C++ style | 
 | guide](https://docs.opentitan.org/doc/rm/c_cpp_coding_style/) where it does not | 
 | contradict with the guidelines below. | 
 |  | 
 | The guidelines below apply to writing DIFs, and code should be written in a | 
 | similar style to the existing DIF libraries in this directory. | 
 |  | 
 | ### Definitions | 
 |  | 
 | <a name="side-effects"></a> | 
 | **Side-effects** include (but are not limited to) writing to memory, including | 
 | memory-mapped hardware, and modifying processor CSRs. | 
 |  | 
 | ### DIF Library Guidance | 
 |  | 
 | * DIF libraries must be written in C. | 
 | * DIF libraries can only depend on the following headers (and their associated | 
 |   libraries): | 
 |   * `sw/device/lib/base/bitfield.h` | 
 |   * `sw/device/lib/base/mmio.h` | 
 |   * `sw/device/lib/base/memory.h` | 
 |   * `sw/device/lib/dif/dif_base.h` | 
 | * DIF libraries must not depend on other DIF libraries. Exercising DIF | 
 |   functionality may require an environment set up using another DIF library, but | 
 |   DIFs must not call DIFs in other DIF libraries. | 
 | * DIF library headers must be polyglot headers for C and C++. | 
 | * the public (manually-implemented) DIF header for each DIF library should | 
 |   `#include` the (private) auto-generated header, so that DIF consumers need | 
 |   only `#include` the public DIF header to make use of an IP's DIF library. | 
 |  | 
 | ### DIF API Guidance | 
 |  | 
 | The following rules specify the basic API that each DIF must conform to. These | 
 | rules specify the names of types, constants, and functions that each DIF must | 
 | define for providing certain kinds of non-device-specific functionality (such as | 
 | initializing handles or managing interrupts). | 
 |  | 
 | Notational caveats: | 
 | * The token `<ip>` is the "short IP name" of the peripheral, | 
 |   in `snake_case` or `PascalCase` as is appropriate. | 
 | * The parameter name `handle` is not normative, and DIF libraries are free to | 
 |   choose a different, but consistent, name for it. | 
 | * All functions below are assumed to return `dif_result_t`, a global DIF return | 
 |   type defined in `sw/device/lib/dif/dif_base.h`. | 
 | * Unless otherwise noted, all symbols mentioned below are required. | 
 |  | 
 | #### Hardware Parameterization | 
 |  | 
 | Our aim is that a single DIF library can be used with multiple instances of the | 
 | same IP on the same chip, even when those IPs have been instantiated with | 
 | different hardware parameters. | 
 |  | 
 | At the moment, we have a good approach to being able to address separate | 
 | hardware instances instantiated at separate addresses, as long as they have the | 
 | same hardware parameters (see the `base_addr` member in `dif_<ip>_t`). | 
 | Most other parameters come from the specific IP on a case-by-case basis, and are | 
 | extracted from the IP's auto-generated register header file, e.g., | 
 | `<ip>_regs.h`. | 
 |  | 
 | #### Base Types | 
 |  | 
 | There are two categories of base types: | 
 | 1. those that are defined once in `sw/device/lib/dif/dif_base.h` and used in all | 
 |    DIF libraries, and | 
 | 2. those that are expected to be defined separately by all DIF libraries (unless | 
 |    otherwise specified). | 
 |  | 
 | The base types defined in `sw/device/lib/dif/dif_base.h` include: | 
 | * `dif_result_t` -- an enum representing global DIF return codes. | 
 | * `dif_toggle_t` -- an enum to be used instead of a `bool` when describing | 
 |   enablement states. | 
 |  | 
 | The base types that are expected to be defined separately by all DIF libraries | 
 | include: | 
 | * `dif_<ip>_t` -- an **auto-generated** type representing a handle to the | 
 |   peripheral. Its first (and only) field is always the base address for the | 
 |   peripheral registers, styled `mmio_region_t base_addr;`. | 
 |   This type is usually passed by `const` pointer, except when it is | 
 |   being initialized (see `dif_<ip>_init()` below). | 
 | * `dif_<ip>_config_t` -- a **manually-defined** struct representing runtime | 
 |   configuration parameters for the peripheral. It is only present when | 
 |   `dif_<ip>_configure()` is defined. This type is always passed by value. | 
 |  | 
 | #### Lifecycle Functions | 
 | The following functions are the basic functionality for initializing and | 
 | handling the lifetime of a handle. | 
 |  | 
 | * `dif_result_t dif_<ip>_init(mmio_region_t base_addr, dif_<ip>_t *handle);` | 
 |   initializes `handle` with with the base address of the instantiated IP this | 
 |   DIF is targeting to use. This DIF is **auto-generated**. | 
 |  | 
 | * `dif_result_t dif_<ip>_configure(const dif_<ip>_t *handle, dif_<ip>_config_t | 
 |   config);` configures the hardware managed by `handle` with runtime parameters | 
 |   in an implementation-defined way. This function should be "one-off": it should | 
 |   only need to be called once for the lifetime of the handle. | 
 |   _If there is no meaningful state to configure, this function may be omitted._ | 
 |   In particular, DIF libraries providing transaction functions will usually have | 
 |   no need for this function at all. This DIF is **manually-implemented**. | 
 |  | 
 | #### Transaction Management | 
 |  | 
 | The following types and functions are the standard interface for | 
 | *transaction-oriented* peripherals, in which a client schedules an operation to | 
 | be completed at some point in the future. All types and functions listed here | 
 | are **manually-implemented**. | 
 |  | 
 | * `dif_<ip>_transaction_t` is a struct representing runtime parameters for | 
 |   starting a hardware transaction. It is only present when `dif_<ip>_start()` is | 
 |   defined. This type is always passed by value. A DIF library my opt to use | 
 |   another pre-existing type instead, when that type provides a more semantically | 
 |   appropriate meaning. | 
 | * `dif_<ip>_output_t` is a struct describing how to output a completed | 
 |   transaction. Often, this will be a type like `uint8_t *`. The same caveats | 
 |   about a DIF library providing a different type apply here. | 
 | * `dif_result_t dif_<ip>_start(const dif_<ip>_t *handle, dif_<ip>_transaction_t | 
 |   transaction);` starts a transaction on a transaction-oriented peripheral. This | 
 |   function may be called multiple times, but each call should be paired with a | 
 |   `dif_<ip>_end()` call. | 
 | * `dif_result_t dif_<ip>_end(const dif_<ip>_t *handle, dif_<ip>_output_t out);` | 
 |   completes a transaction started with `dif_<ip>_start()`, writing its results | 
 |   to a location specified in `out`. | 
 |  | 
 | If a peripheral supports multiple transaction modes with incompatible parameter | 
 | types, the above names may be duplicated by inserting `mode_<mode>` after `<ip>`. | 
 | For example, | 
 | ``` | 
 | dif_result_t dif_<ip>_mode_<mode>_end(const dif_<ip>_t *handle, | 
 |                                   dif_<ip>_mode_<mode>_output_t out); | 
 | ``` | 
 | There is no requirement that `_start()` and `_end()` share the same set of | 
 | `<mode>`s; for example, there might be a single `dif_<ip>_start()` but many | 
 | `dif_<ip>_mode_<mode>_end()`s. This style of API is preferred over using | 
 | `union`s with `dif_<ip>_transaction_t` and `dif_<ip>_output_t`. | 
 |  | 
 | #### Register Locking | 
 |  | 
 | The following functions are the standard interface for peripherals that can lock | 
 | portions of their software-accessible functionality. All types and functions | 
 | listed here are **manually-implemented**. | 
 |  | 
 | * `kDifLocked` is the global return result enum of an operation that can be | 
 |   locked out. DIFs which may fail due to lockout, which is software-detectable, | 
 |   should return this value when possible. | 
 | * `dif_result_t dif_<ip>_lock(const dif_<ip>_t *handle);` locks out all portions | 
 |   of the peripheral which can be locked. If a peripheral can be locked-out | 
 |   piecewise, `dif_<ip>_lock_<operation>()` functions may be provided alongside | 
 |   or in lieu of `dif_<ip>_lock()`. | 
 | * `dif_result_t dif_<ip>_is_locked(const dif_<ip>_t *handle, bool *is_locked);` | 
 |   checks whether the peripheral has been locked out. As with `dif_<ip>_lock()`, | 
 |   DIF libraries may provide a piecewise version of this API. | 
 |  | 
 | #### Interrupt Management | 
 |  | 
 | The following types and functions are the standard interface for peripherals that | 
 | provide a collection of `INTR_ENABLE`, `INTR_STATE`, and `INTR_TEST` registers | 
 | for interrupt management. A DIF library for a peripheral providing such | 
 | registers must provide this interface. To ensure this, all interrupt DIFs, | 
 | including: headers, (C) implementations, and unit tests, are *auto-generated* from | 
 | templates and an IP's HJSON configuration file using the `util/make_new_dif.py` | 
 | tool (described above). | 
 |  | 
 | If a peripheral is defined with `no_auto_intr_regs: true`, this exact API is not | 
 | required even if the `INTR_` registers are provided (though DIF libraries are | 
 | encouraged to follow it where it makes sense). _In these cases, auto-generated | 
 | interrupt DIFs may not exist._ | 
 |  | 
 | * `dif_<ip>_irq_t` is an enum that lists all of the interrupt types for this | 
 |   peripheral. These derived from the `interrupt_list` attribute within an IP's | 
 |   HJSON file. | 
 | * `dif_result_t dif_<ip>_irq_get_state(const dif_<ip>_t *handle, | 
 |   dif_<ip>_irq_state_snapshot_t *snapshot, bool *is_pending);` returns a | 
 |   snapshot of the entire interrupt state register, to check the status of all | 
 |   interrupts for a peripheral. | 
 | * `dif_result_t dif_<ip>_irq_is_pending(const dif_<ip>_t *handle, dif_<ip>_irq_t | 
 |   irq, bool *is_pending);` checks whether a specific interrupt is | 
 |   pending (i.e., if the interrupt has been asserted but not yet cleared). | 
 | * `dif_result_t dif_<ip>_irq_acknowledge_all(const dif_<ip>_t *handle);` | 
 |   acknowledges all interrupts have been serviced, marking them as | 
 |   complete by clearing all pending bits. This function does nothing and returns | 
 |   `kDifOk` if no interrupts were pending. | 
 | * `dif_result_t dif_<ip>_irq_acknowledge(const dif_<ip>_t *handle, dif_<ip>_irq_t | 
 |   irq);` acknowledges that an interrupt has been serviced, marking it as | 
 |   complete by clearing its pending bit. This function does nothing and returns | 
 |   `kDifOk` if the interrupt wasn't pending. | 
 | * `dif_result_t dif_<ip>_irq_get_enabled(const dif_<ip>_t *handle, dif_<ip>_irq_t | 
 |   irq, const dif_<ip>_toggle_t *state);` gets whether an interrupt is | 
 |   enabled (i.e., masked). | 
 | * `dif_result_t dif_<ip>_irq_set_enabled(const dif_<ip>_t *handle, dif_<ip>_irq_t | 
 |   irq, dif_<ip>_toggle_t state);` sets whether a particular interrupt is | 
 |   enabled (i.e., masked). | 
 | * `dif_result_t dif_<ip>_irq_force(const dif_<ip>_t *handle, dif_<ip>_irq_t | 
 |   irq);` forcibly asserts a specific interrupt, causing it to be serviced | 
 |   as if hardware had triggered it. | 
 |  | 
 | Additionally, the following types allow for batch save/restore operations on | 
 | the interrupt enable register: | 
 |  | 
 | * `dif_<ip>_irq_enable_snapshot_t` is a type that encapsulates restorable | 
 |   interrupt enablement state, to be used with the two functions below. This type | 
 |   should be treated as opaque by clients. | 
 | * `dif_result_t dif_<ip>_irq_disable_all(const dif_<ip>_t *handle, | 
 |   dif_<ip>_irq_enable_snapshot_t *snapshot);` disables all interrupts associated | 
 |   with the peripheral, saving them to `*snapshot`. `snapshot` may be null, in | 
 |   which case the previous enablement state is not saved. | 
 | * `dif_result_t dif_<ip>_irq_restore_all(const dif_<ip>_t *handle, | 
 |   const dif_<ip>_irq_enable_snapshot_t *snapshot);` restores an interrupt | 
 |   enablement snapshot produced by the above function. | 
 |  | 
 | #### Unit Testing | 
 |  | 
 | Each DIF has an associated unit test, written in C++. For auto-generated DIFs, | 
 | their associated unit tests are also auto-generated. For manually-implemented | 
 | DIFs, their associated unit tests follow the conventions: | 
 | * The whole file is wrapped in the `dif_<ip>_unittest` namespace. | 
 | * There is a base class for all test fixtures, named `<ip>Test`, which derives | 
 |   `testing::Test` and `mock_mmio::MmioTest`. | 
 | * Each function has an associated test fixture, usually named | 
 |   `<function>Test`, which derives `<ip>Test`. Multiple similar functions may be | 
 |   grouped under one fixture. | 
 | * Prefer to use expectation macros, like `EXPECT_DIF_OK`, defined in | 
 |   `dif_test_base.h` whenever possible (e.g. do not write | 
 |   `EXPECT_EQ(<long expression>, kDifOk);`). | 
 |  | 
 | ### DIF Style Guidance | 
 |  | 
 | The following rules must be followed by public DIF functions (those declared in | 
 | the DIF library's header file). Internal DIF functions (those declared `static` | 
 | and not declared in the DIF library's header file) should follow these rules but | 
 | there are some relaxations of these rules for them described at the end. | 
 |  | 
 | * DIF declarations must match their definitions exactly. | 
 |   * Scalar arguments must not be declared `const` or `volatile` (cv-qualified) | 
 |     in DIF signatures. | 
 |  | 
 | * DIFs must use one of the `dif_result_t` enums (described in | 
 |   `sw/device/lib/dif/dif_base.h`) rather than booleans for reporting errors. If | 
 |   a DIF can either error or instead produce a value, it must return a | 
 |   `dif_result_t`, and use an out-parameter for returning the produced value. | 
 |   * DIFs that return an enum return code must be annotated with | 
 |     `OT_WARN_UNUSED_RESULT`, to help minimize mistakes from | 
 |     failing to check a result. This guidance applies to `static` helper | 
 |     functions that return an error of some kind as well. | 
 |   * DIFs that cannot error and that do not return a value must return `void`. | 
 |  | 
 | * DIFs must check their arguments against preconditions using "guard | 
 |   statements". A guard statement is a simple if statement at the start of a | 
 |   function which only returns an error code if the preconditions are not met. | 
 |   Guard statements must cover the following checks: | 
 |   * DIFs must ensure their pointer arguments are non-null, unless that pointer | 
 |     is for an optional out-parameter. Arguments typed `mmio_region_t` are not | 
 |     pointers, and cannot meaningfully be checked for non-nullness. | 
 |   * DIFs must ensure, if they only accept a subset of an enum, that the argument | 
 |     is within that subset. However, DIFs may assume, for checking preconditions, | 
 |     that any enum argument is one of the enum constants. | 
 |   * DIFs must not cause any side-effects before any guard statements. This means | 
 |     returning early from a guard statement must not leave the hardware in an | 
 |     invalid or unrecoverable state. | 
 |  | 
 | * Switch statements in DIFs must always have a default case, including when | 
 |   switching on an enum value (an "enum switch"). | 
 |   * The default case of an enum switch must report an error for values that are | 
 |     not a constant from that enum. In the absence of more specific information, | 
 |     this should return `kDifError` or the equivalent return code value from | 
 |     a global DIF return code enum. If the enum switch is part of a guard | 
 |     statement, it may return `kDifBadArg` instead. | 
 |   * Enum switches do not need a `case` for enum constants that are unreachable | 
 |     due to a guard statement. | 
 |  | 
 | * DIFs must use `sw/device/lib/base/mmio.h` for accessing memory-mapped | 
 |   hardware. DIFs must not use `sw/device/lib/base/memory.h` for accessing | 
 |   memory-mapped hardware. | 
 |  | 
 | * Internal DIF functions, which are not intended to be part of a public DIF | 
 |   library interface, must not be declared in the DIF library header, and must be | 
 |   marked `static`. | 
 |   * `static` DIF functions should not be marked `static inline`. | 
 |   * An internal DIF function does not need to check preconditions, if all the | 
 |     DIF functions that call it have already checked that precondition. |