| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #ifndef OPENTITAN_SW_DEVICE_LIB_BASE_CSR_H_ |
| #define OPENTITAN_SW_DEVICE_LIB_BASE_CSR_H_ |
| |
| #include <assert.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| |
| #include "sw/device/lib/base/csr_registers.h" |
| #include "sw/device/lib/base/macros.h" |
| #include "sw/device/lib/base/stdasm.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif // __cplusplus |
| |
| /** |
| * @file |
| * @brief Ibex Control and Status Register (CSR) interface. |
| * |
| * A set of macros that provide both read and modify operations on Ibex CSRs. |
| * Compiling translation units that include this header file with `-DMOCK_CSR` |
| * will result in the CSR operations being replaced with a mocked |
| * implementation. |
| */ |
| |
| /** |
| * Define the implementation macros. |
| * |
| * The implementation used depends on whether the CSR library is providing a |
| * real or a mocked interface. |
| */ |
| #ifndef OT_PLATFORM_RV32 |
| |
| /** |
| * Macro to check that an argument is a constant expression at compile time. |
| * |
| * The real implementations of CSR operations require the CSR address to be |
| * a constant expression. Using this macro allows the same constraint to be |
| * applied when using the mocked implementations. |
| * |
| * Note: could also use a static assertion for this but an inline asm immediate |
| * constraint means the error for mocked and real implementation should be very |
| * similar. |
| */ |
| #define CSR_FORCE_CONST_EXPR(x) asm volatile("" ::"i"(x)) |
| |
| uint32_t mock_csr_read(uint32_t addr); |
| |
| #define CSR_READ_IMPL(csr, dest) \ |
| do { \ |
| static_assert(sizeof(*dest) == sizeof(uint32_t), \ |
| "dest must point to a 4-byte variable"); \ |
| CSR_FORCE_CONST_EXPR(csr); \ |
| *dest = mock_csr_read(csr); \ |
| } while (false) |
| |
| void mock_csr_write(uint32_t addr, uint32_t value); |
| |
| #define CSR_WRITE_IMPL(csr, val) \ |
| do { \ |
| static_assert(sizeof(val) == sizeof(uint32_t), \ |
| "val must be a 4-byte value"); \ |
| CSR_FORCE_CONST_EXPR(csr); \ |
| mock_csr_write(csr, val); \ |
| } while (false) |
| |
| void mock_csr_set_bits(uint32_t addr, uint32_t mask); |
| |
| #define CSR_SET_BITS_IMPL(csr, mask) \ |
| do { \ |
| static_assert(sizeof(mask) == sizeof(uint32_t), \ |
| "mask must be a 4-byte value"); \ |
| CSR_FORCE_CONST_EXPR(csr); \ |
| mock_csr_set_bits(csr, mask); \ |
| } while (false) |
| |
| void mock_csr_clear_bits(uint32_t addr, uint32_t mask); |
| |
| #define CSR_CLEAR_BITS_IMPL(csr, mask) \ |
| do { \ |
| static_assert(sizeof(mask) == sizeof(uint32_t), \ |
| "mask must be a 4-byte value"); \ |
| CSR_FORCE_CONST_EXPR(csr); \ |
| mock_csr_clear_bits(csr, mask); \ |
| } while (false) |
| |
| #else // OT_PLATFORM_RV32 |
| |
| #define CSR_READ_IMPL(csr, dest) \ |
| do { \ |
| static_assert(sizeof(*dest) == sizeof(uint32_t), \ |
| "dest must point to a 4-byte variable"); \ |
| asm volatile("csrr %0, %1;" : "=r"(*dest) : "i"(csr)); \ |
| } while (false) |
| |
| #define CSR_WRITE_IMPL(csr, val) \ |
| do { \ |
| static_assert(sizeof(val) == sizeof(uint32_t), \ |
| "val must be a 4-byte value"); \ |
| asm volatile("csrw %0, %1;" ::"i"(csr), "r"(val)); \ |
| } while (false) |
| |
| #define CSR_SET_BITS_IMPL(csr, mask) \ |
| do { \ |
| static_assert(sizeof(mask) == sizeof(uint32_t), \ |
| "mask must be a 4-byte value"); \ |
| asm volatile("csrs %0, %1;" ::"i"(csr), "r"(mask)); \ |
| } while (false) |
| |
| #define CSR_CLEAR_BITS_IMPL(csr, mask) \ |
| do { \ |
| static_assert(sizeof(mask) == sizeof(uint32_t), \ |
| "mask must be a 4-byte value"); \ |
| asm volatile("csrc %0, %1;" ::"i"(csr), "r"(mask)); \ |
| } while (false) |
| |
| #endif // OT_PLATFORM_RV32 |
| |
| /** |
| * Read the value of a CSR and place the result into the location pointed to by |
| * dest. |
| * |
| * Equivalent to: |
| * |
| * `*dest = csr` |
| * |
| * @param csr The target register. MUST be a `CSR_REG_<name>` constant. |
| * @param[out] dest Pointer to a variable where the value of the named CSR will |
| * be written to. |
| */ |
| #define CSR_READ(csr, dest) CSR_READ_IMPL(csr, dest) |
| |
| /** |
| * Write a value to a CSR. |
| * |
| * Equivalent to: |
| * |
| * `csr = val` |
| * |
| * @param csr The target register. MUST be a `CSR_REG_<name>` constant. |
| * @param val The value to write to the named CSR. |
| */ |
| #define CSR_WRITE(csr, val) CSR_WRITE_IMPL(csr, val) |
| |
| /** |
| * Set masked bits in the CSR. |
| * |
| * Equivalent to: |
| * |
| * `csr |= mask` |
| * |
| * @param csr The target register. MUST be a `CSR_REG_<name>` constant. |
| * @param mask Mask containing the bits to set. |
| */ |
| #define CSR_SET_BITS(csr, mask) CSR_SET_BITS_IMPL(csr, mask) |
| |
| /** |
| * Clear masked bits in the CSR. |
| * |
| * Equivalent to: |
| * |
| * `csr &= ~mask` |
| * |
| * @param csr The target register. MUST be a `CSR_REG_<name>` constant. |
| * @param mask Mask containing the bits to clear. |
| */ |
| #define CSR_CLEAR_BITS(csr, mask) CSR_CLEAR_BITS_IMPL(csr, mask) |
| |
| #ifdef __cplusplus |
| } // extern "C" |
| #endif // __cplusplus |
| |
| #endif // OPENTITAN_SW_DEVICE_LIB_BASE_CSR_H_ |