Software APIs
csr.h
Go to the documentation of this file.
1 // Copyright lowRISC contributors.
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #ifndef OPENTITAN_SW_DEVICE_LIB_BASE_CSR_H_
6 #define OPENTITAN_SW_DEVICE_LIB_BASE_CSR_H_
7 
8 #include <stdbool.h>
9 #include <stdint.h>
10 
11 #include "sw/device/lib/base/csr_registers.h"
13 
14 #ifdef __cplusplus
15 extern "C" {
16 #endif // __cplusplus
17 
18 /**
19  * @file
20  * @brief Ibex Control and Status Register (CSR) interface.
21  *
22  * A set of macros that provide both read and modify operations on Ibex CSRs.
23  * Compiling translation units that include this header file with `-DMOCK_CSR`
24  * will result in the CSR operations being replaced with a mocked
25  * implementation.
26  */
27 
28 /**
29  * Portable (C and C++) static assertion.
30  *
31  * TODO: replace with static_assert macro in C (assert.h does this)?
32  */
33 #ifdef __cplusplus
34 #define CSR_STATIC_ASSERT static_assert
35 #else // __cplusplus
36 #define CSR_STATIC_ASSERT _Static_assert
37 #endif // __cplusplus
38 
39 /**
40  * Define the implementation macros.
41  *
42  * The implementation used depends on whether the CSR library is providing a
43  * real or a mocked interface.
44  */
45 #ifdef MOCK_CSR
46 
47 /**
48  * Macro to check that an argument is a constant expression at compile time.
49  *
50  * The real implementations of CSR operations require the CSR address to be
51  * a constant expression. Using this macro allows the same constraint to be
52  * applied when using the mocked implementations.
53  *
54  * Note: could also use a static assertion for this but an inline asm immediate
55  * constraint means the error for mocked and real implementation should be very
56  * similar.
57  */
58 #define CSR_FORCE_CONST_EXPR(x) asm volatile("" ::"i"(x))
59 
60 uint32_t mock_csr_read(uint32_t addr);
61 
62 #define CSR_READ_IMPL(csr, dest) \
63  do { \
64  CSR_STATIC_ASSERT(sizeof(*dest) == sizeof(uint32_t), \
65  "dest must point to a 4-byte variable"); \
66  CSR_FORCE_CONST_EXPR(csr); \
67  *dest = mock_csr_read(csr); \
68  } while (false)
69 
70 void mock_csr_write(uint32_t addr, uint32_t value);
71 
72 #define CSR_WRITE_IMPL(csr, val) \
73  do { \
74  CSR_STATIC_ASSERT(sizeof(val) == sizeof(uint32_t), \
75  "val must be a 4-byte value"); \
76  CSR_FORCE_CONST_EXPR(csr); \
77  mock_csr_write(csr, val); \
78  } while (false)
79 
80 void mock_csr_set_bits(uint32_t addr, uint32_t mask);
81 
82 #define CSR_SET_BITS_IMPL(csr, mask) \
83  do { \
84  CSR_STATIC_ASSERT(sizeof(mask) == sizeof(uint32_t), \
85  "mask must be a 4-byte value"); \
86  CSR_FORCE_CONST_EXPR(csr); \
87  mock_csr_set_bits(csr, mask); \
88  } while (false)
89 
90 void mock_csr_clear_bits(uint32_t addr, uint32_t mask);
91 
92 #define CSR_CLEAR_BITS_IMPL(csr, mask) \
93  do { \
94  CSR_STATIC_ASSERT(sizeof(mask) == sizeof(uint32_t), \
95  "mask must be a 4-byte value"); \
96  CSR_FORCE_CONST_EXPR(csr); \
97  mock_csr_clear_bits(csr, mask); \
98  } while (false)
99 
100 #else // MOCK_CSR
101 
102 #define CSR_READ_IMPL(csr, dest) \
103  do { \
104  CSR_STATIC_ASSERT(sizeof(*dest) == sizeof(uint32_t), \
105  "dest must point to a 4-byte variable"); \
106  asm volatile("csrr %0, %1;" : "=r"(*dest) : "i"(csr)); \
107  } while (false)
108 
109 #define CSR_WRITE_IMPL(csr, val) \
110  do { \
111  CSR_STATIC_ASSERT(sizeof(val) == sizeof(uint32_t), \
112  "val must be a 4-byte value"); \
113  asm volatile("csrw %0, %1;" ::"i"(csr), "r"(val)); \
114  } while (false)
115 
116 #define CSR_SET_BITS_IMPL(csr, mask) \
117  do { \
118  CSR_STATIC_ASSERT(sizeof(mask) == sizeof(uint32_t), \
119  "mask must be a 4-byte value"); \
120  asm volatile("csrs %0, %1;" ::"i"(csr), "r"(mask)); \
121  } while (false)
122 
123 #define CSR_CLEAR_BITS_IMPL(csr, mask) \
124  do { \
125  CSR_STATIC_ASSERT(sizeof(mask) == sizeof(uint32_t), \
126  "mask must be a 4-byte value"); \
127  asm volatile("csrc %0, %1;" ::"i"(csr), "r"(mask)); \
128  } while (false)
129 
130 #endif // MOCK_CSR
131 
132 /**
133  * Read the value of a CSR and place the result into the location pointed to by
134  * dest.
135  *
136  * Equivalent to:
137  *
138  * `*dest = csr`
139  *
140  * @param csr The target register. MUST be a `CSR_REG_<name>` constant.
141  * @param[out] dest Pointer to a variable where the value of the named CSR will
142  * be written to.
143  */
144 #define CSR_READ(csr, dest) CSR_READ_IMPL(csr, dest)
145 
146 /**
147  * Write a value to a CSR.
148  *
149  * Equivalent to:
150  *
151  * `csr = val`
152  *
153  * @param csr The target register. MUST be a `CSR_REG_<name>` constant.
154  * @param val The value to write to the named CSR.
155  */
156 #define CSR_WRITE(csr, val) CSR_WRITE_IMPL(csr, val)
157 
158 /**
159  * Set masked bits in the CSR.
160  *
161  * Equivalent to:
162  *
163  * `csr |= mask`
164  *
165  * @param csr The target register. MUST be a `CSR_REG_<name>` constant.
166  * @param mask Mask containing the bits to set.
167  */
168 #define CSR_SET_BITS(csr, mask) CSR_SET_BITS_IMPL(csr, mask)
169 
170 /**
171  * Clear masked bits in the CSR.
172  *
173  * Equivalent to:
174  *
175  * `csr &= ~mask`
176  *
177  * @param csr The target register. MUST be a `CSR_REG_<name>` constant.
178  * @param mask Mask containing the bits to clear.
179  */
180 #define CSR_CLEAR_BITS(csr, mask) CSR_CLEAR_BITS_IMPL(csr, mask)
181 
182 #ifdef __cplusplus
183 } // extern "C"
184 #endif // __cplusplus
185 
186 #endif // OPENTITAN_SW_DEVICE_LIB_BASE_CSR_H_