1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * Template code (macros) for the most typical/repetitive
9  * code of the HW models
10  *
11  * The _si versions are for peripheral which can only have one instance
12  */
13 #ifndef _NRF_HW_MODEL_NHW_TEMPLATES_H
14 #define _NRF_HW_MODEL_NHW_TEMPLATES_H
15 
16 #include "NHW_config.h"
17 
18 /*
19  * TASKS register write side-effects
20  * (just calls thru to the task)
21  */
22 #define NHW_SIDEEFFECTS_TASKS_si(peri, task) \
23   void nhw_##peri##_regw_sideeffects_TASKS_##task(void) { \
24     if ( NRF_##peri##_regs.TASKS_##task ) { \
25       NRF_##peri##_regs.TASKS_##task = 0; \
26       nhw_##peri##_TASK_##task(); \
27     } \
28   }
29 
30 #define NHW_SIDEEFFECTS_TASKS(peri, peri_regs, task) \
31   void nhw_##peri##_regw_sideeffects_TASKS_##task(unsigned int inst) { \
32     if ( peri_regs TASKS_##task ) { \
33       peri_regs TASKS_##task = 0; \
34       nhw_##peri##_TASK_##task(inst); \
35     } \
36   }
37 
38 /*
39  * version of NHW_SIDEEFFECTS_TASKS() where the task is in a struct
40  */
41 #define NHW_SIDEEFFECTS_TASKS_ST(peri, peri_regs, task, taskst) \
42   void nhw_##peri##_regw_sideeffects_TASKS_##task(unsigned int inst) { \
43     if ( peri_regs TASKS_##taskst ) { \
44       peri_regs TASKS_##taskst = 0; \
45       nhw_##peri##_TASK_##task(inst); \
46     } \
47   }
48 
49 /*
50  * SUBSCRIBE register write side-effects
51  */
52 #define NHW_SIDEEFFECTS_SUBSCRIBE_si(peri, task) \
53   void nhw_##peri##_regw_sideeffects_SUBSCRIBE_##task(unsigned int inst) { \
54     static struct nhw_subsc_mem task##_subscribed[NHW_##peri##_TOTAL_INST]; \
55     nhw_dppi_common_subscribe_sideeffect(nhw_##peri##_dppi_map[inst], \
56         NRF_##peri##_regs.SUBSCRIBE_##task, \
57         &task##_subscribed[inst], \
58         (dppi_callback_t)nhw_##peri##_TASK_##task, \
59         DPPI_CB_NO_PARAM); \
60   }
61 
62 /*
63  * Any EVENT register write side-effect
64  */
65 #define NHW_SIDEEFFECTS_EVENTS(peri) \
66   void nhw_##peri##_regw_sideeffects_EVENTS_all(unsigned int inst) { \
67     nhw_##peri##_eval_interrupt(inst); \
68   }
69 
70 
71 #if (NHW_HAS_PPI)
72   #define _NHW_XPPI_EVENT(peri, peri_regs, inst, event)    \
73     nrf_ppi_event(peri##_EVENTS_##event)
74 #elif (NHW_HAS_DPPI)
75   #define _NHW_XPPI_EVENT(peri, peri_regs, inst, event)    \
76      nhw_dppi_event_signal_if(nhw_##peri##_dppi_map[inst], \
77                               peri_regs PUBLISH_##event)
78 #endif /* (NHW_HAS_PPI) / (NHW_HAS_DPPI)*/
79 
80 
81 #define _NHW_SIGNAL_EVENT_body(peri, peri_regs, event) \
82   { \
83     peri_regs EVENTS_##event = 1; \
84     nhw_##peri##_eval_interrupt(inst); \
85     _NHW_XPPI_EVENT(peri, peri_regs, inst, event); \
86   }
87 
88 /*
89  * Signal an event:
90  *  * Set the corresponding event register
91  *  * Cause level interrupts to be reevaluated
92  *  * Send the event either to the PPI or DPPI (if enabled)
93  *
94  * NOTE: Cannot be used for events with shortcuts
95  * NOTE: Cannot be used for multi-instance peripherals connected to the PPI
96  */
97 #define NHW_SIGNAL_EVENT(peri, peri_regs, event) \
98   void nhw_##peri##_signal_EVENTS_##event(unsigned int inst) \
99     _NHW_SIGNAL_EVENT_body(peri, peri_regs, event)
100 
101 /*
102  * Signal an event. Like NHW_SIGNAL_EVENT()
103  * but when the event has shortcuts.
104  *
105  * NOTE: Cannot be used for multi-instance peripherals connected to the PPI
106  */
107 #define NHW_SIGNAL_EVENT_ns(peri, peri_regs, event) \
108   void nhw_##peri##_signal_EVENTS_##event##_noshort(unsigned int inst) \
109     _NHW_SIGNAL_EVENT_body(peri, peri_regs, event)
110 
111 #define NHW_SIGNAL_EVENT_si(peri, event) \
112     NHW_SIGNAL_EVENT(peri, NRF_##peri##_regs. , event)
113 
114 #define NHW_SIGNAL_EVENT_ns_si(peri, event) \
115     NHW_SIGNAL_EVENT_ns(peri, NRF_##peri##_regs. , event)
116 
117 #define NHW_SIDEEFFECTS_INTSET_si(peri, peri_regs, inten)\
118   void nhw_##peri##_regw_sideeffects_INTENSET(void) { \
119     if ( peri_regs INTENSET ){ /* LCOV_EXCL_BR_LINE */\
120       inten |= peri_regs INTENSET;                    \
121       peri_regs INTENSET = inten;                     \
122       nhw_##peri##_eval_interrupt(0);                \
123     }                                                 \
124   }
125 
126 #define NHW_SIDEEFFECTS_INTCLR_si(peri, peri_regs, inten) \
127   void nhw_##peri##_regw_sideeffects_INTENCLR(void) { \
128     if ( peri_regs INTENCLR ){/* LCOV_EXCL_BR_LINE */ \
129        inten &= ~(peri_regs INTENCLR);                \
130        peri_regs INTENSET = inten;                    \
131        peri_regs INTENCLR = 0;                        \
132        nhw_##peri## _eval_interrupt(0);               \
133     }                                                 \
134   }
135 
136 #define NHW_SIDEEFFECTS_INTSET(peri, peri_regs, inten) \
137   void nhw_##peri##_regw_sideeffects_INTENSET(uint inst) { \
138     if ( peri_regs INTENSET ){ /* LCOV_EXCL_BR_LINE */\
139       inten |= peri_regs INTENSET;                    \
140       peri_regs INTENSET = inten;                     \
141       nhw_##peri##_eval_interrupt(inst);              \
142     }                                                 \
143   }
144 
145 #define NHW_SIDEEFFECTS_INTEN(peri, peri_regs, inten) \
146   void nhw_##peri##_regw_sideeffects_INTEN(uint inst) { \
147     peri_regs INTENSET = inten;                     \
148     nhw_##peri##_eval_interrupt(inst);              \
149   }
150 
151 #define NHW_SIDEEFFECTS_INTCLR(peri, peri_regs, inten) \
152   void nhw_##peri##_regw_sideeffects_INTENCLR(uint inst) { \
153     if ( peri_regs INTENCLR ){/* LCOV_EXCL_BR_LINE */ \
154        inten &= ~(peri_regs INTENCLR);                \
155        peri_regs INTENSET = inten;                    \
156        peri_regs INTENCLR = 0;                        \
157        nhw_##peri## _eval_interrupt(inst);            \
158     }                                                 \
159   }
160 
161 #define NHW_CHECK_INTERRUPT(peri, peri_regs, event, inten) \
162   if (peri_regs EVENTS_##event && (inten &  peri##_INTENSET_##event##_Msk)){ \
163     new_int_line = true; \
164   }
165 
166 /*
167  * version of NHW_CHECK_INTERRUPT() where the event is in a struct
168  */
169 #define NHW_CHECK_INTERRUPT_ST(peri, peri_regs, event, intevnt, inten) \
170   if (peri_regs EVENTS_##event && (inten &  peri##_INTENSET_##intevnt##_Msk)){ \
171     new_int_line = true; \
172   }
173 
174 #define NHW_CHECK_INTERRUPT_si(peri, event, inten) \
175   if (NRF_##peri##_regs.EVENTS_##event && (inten &  peri##_INTENSET_##event##_Msk)){ \
176     new_int_line = true; \
177   }
178 
179 #define NHW_SHORT_si(peri, event, task) \
180   if (NRF_##peri##_regs.SHORTS & peri##_SHORTS_##event##_##task##_Msk) { \
181     nhw_##peri##_TASK_##task(); \
182   }
183 
184 #define NHW_SHORT(peri, inst, peri_regs, event, task) \
185   if (peri_regs SHORTS & peri##_SHORTS_##event##_##task##_Msk) { \
186     nhw_##peri##_TASK_##task(inst); \
187   }
188 
189 /*
190  * version of NHW_SHORT() where the task is in a struct
191  */
192 #define NHW_SHORT_ST(peri, inst, peri_regs, event, task, task_st) \
193   if (peri_regs SHORTS & peri##_SHORTS_##event##_##task_st##_Msk) { \
194     nhw_##peri##_TASK_##task(inst); \
195   }
196 
197 #endif /* _NRF_HW_MODEL_NHW_TEMPLATES_H */
198