KallistiOS git master
Independent SDK for the Sega Dreamcast
Loading...
Searching...
No Matches
irq.h
Go to the documentation of this file.
1/* KallistiOS ##version##
2
3 arch/dreamcast/include/arch/irq.h
4 Copyright (C) 2000, 2001 Megan Potter
5 Copyright (C) 2024 Paul Cercueil
6 Copyright (C) 2024, 2025 Falco Girgis
7
8*/
9
10/** \file arch/irq.h
11 \brief Interrupt and exception handling.
12 \ingroup irqs
13
14 This file contains various definitions and declarations related to handling
15 interrupts and exceptions on the Dreamcast. This level deals with IRQs and
16 exceptions generated on the SH4, versus the asic layer which deals with
17 actually differentiating "external" interrupts.
18
19 \author Megan Potter
20 \author Paul Cercueil
21 \author Falco Girgis
22
23 \see dc/asic.h
24*/
25
26/* Keep this include above the macro guards */
27#include <kos/irq.h>
28
29#ifndef __ARCH_IRQ_H
30#define __ARCH_IRQ_H
31
32#include <stdalign.h>
33#include <stdbool.h>
34#include <stdint.h>
35#include <kos/cdefs.h>
36__BEGIN_DECLS
37
38/** \defgroup irqs Interrupts
39 \brief IRQs and ISRs for the SH4's CPU
40 \ingroup system
41
42 This is an API for managing interrupts, their masks, and their
43 handler routines along with thread context information.
44
45 \warning
46 This is a low-level, internal kernel API. Many of these
47 interrupts are utilized by various KOS drivers and have higher-level APIs
48 for hooking into them. Care must be taken to not interfere with the IRQ
49 handling which is being done by in-use KOS drivers.
50
51 \note
52 The naming convention used by this API differs from that of the actual SH4
53 manual for historical reasons (it wasn't platform-specific). The SH4 manual
54 refers to the most general type of CPU events which result in a SW
55 callback as "exceptions," with "interrupts" and "general exceptions" being
56 subtypes of exceptions. This API uses the term "interrupt" and "exception"
57 interchangeably, except where it is explicitly noted that "SH4 interrupts"
58 or "SH4 general exceptions" are being referred to, more specifically.
59
60 @{
61*/
62
63/** \defgroup irq_context Context
64 \brief Thread execution state and accessors
65
66 This API includes the structure and accessors for a
67 thread's context state, which contains the registers that are stored
68 and loaded upon thread context switches, which are passed back to
69 interrupt handlers.
70
71 @{
72*/
73
74/** The number of bytes required to save thread context.
75
76 This should include all general CPU registers, FP registers, and status regs
77 (even if not all of these are actually used).
78
79 \note
80 On the Dreamcast, we need `228` bytes for all of that, but we round it up to a
81 nicer number for sanity.
82*/
83#define REG_BYTE_CNT 256
84
85/** Architecture-specific structure for holding the processor state.
86
87 This structure should hold register values and other important parts of the
88 processor state.
89
90 \note
91 The size of this structure should be less than or equal to the
92 \ref REG_BYTE_CNT value.
93*/
94struct __attribute__((aligned(32))) irq_context {
95 uint32_t pc; /**< Program counter */
96 uint32_t pr; /**< Procedure register (aka return address) */
97 uint32_t gbr; /**< Global base register (TLS segment ptr) */
98 uint32_t vbr; /**< Vector base register */
99 uint32_t mach; /**< Multiply-and-accumulate register (high) */
100 uint32_t macl; /**< Multiply-and-accumulate register (low) */
101 uint32_t sr; /**< Status register */
102 uint32_t fpul; /**< Floating-point communication register */
103 uint32_t fr[16]; /**< Primary floating point registers */
104 uint32_t frbank[16]; /**< Secondary floating point registers */
105 uint32_t r[16]; /**< 16 general purpose (integer) registers */
106 uint32_t fpscr; /**< Floating-point status/control register */
107};
108
109/** \name Register Accessors
110 \brief Convenience macros for accessing context registers
111 @{
112*/
113/** Fetch the program counter from an irq_context_t.
114 \param c The context to read from.
115 \return The program counter value.
116*/
117#define CONTEXT_PC(c) ((c).pc)
118
119/** Fetch the frame pointer from an irq_context_t.
120 \param c The context to read from.
121 \return The frame pointer value.
122*/
123#define CONTEXT_FP(c) ((c).r[14])
124
125/** Fetch the stack pointer from an irq_context_t.
126 \param c The context to read from.
127 \return The stack pointer value.
128*/
129#define CONTEXT_SP(c) ((c).r[15])
130
131/** Fetch the return value from an irq_context_t.
132 \param c The context to read from.
133 \return The return value.
134*/
135#define CONTEXT_RET(c) ((c).r[0])
136/** @} */
137
138/** @} */
139
140/** Interrupt exception codes
141
142 SH-specific exception codes. Used to identify the source or type of an
143 interrupt. Each exception code is of a certain "type" which dictates how the
144 interrupt is generated and handled.
145
146 List of exception types:
147
148 |Type | Description
149 |--------|------------
150 |`RESET` | Caused by system reset. Uncatchable and fatal. Automatically branch to address `0xA0000000`.
151 |`REEXEC`| Restarts current instruction after interrupt processing. Context PC is the triggering instruction.
152 |`POST` | Continues with next instruciton after interrupt processing. Context PC is the next instruction.
153 |`SOFT` | Software-driven exceptions for triggering interrupts upon special events.
154 |`UNUSED`| Known to not be present and usable with the DC's SH4 configuration.
155 |`TRAP ` | Virtual type (not a SH hardware type) for trap codes.
156
157 List of exception codes:
158*/
159enum irq_exception
160#ifdef __cplusplus
161: unsigned int
162#endif
163{
164 EXC_RESET_POWERON = 0x0000, /**< `[RESET ]` Power-on reset */
165 EXC_RESET_MANUAL = 0x0020, /**< `[RESET ]` Manual reset */
166 EXC_RESET_UDI = 0x0000, /**< `[RESET ]` Hitachi UDI reset */
167 EXC_ITLB_MULTIPLE = 0x0140, /**< `[RESET ]` Instruction TLB multiple hit */
168 EXC_DTLB_MULTIPLE = 0x0140, /**< `[RESET ]` Data TLB multiple hit */
169 EXC_USER_BREAK_PRE = 0x01e0, /**< `[REEXEC]` User break before instruction */
170 EXC_INSTR_ADDRESS = 0x00e0, /**< `[REEXEC]` Instruction address */
171 EXC_ITLB_MISS = 0x0040, /**< `[REEXEC]` Instruction TLB miss */
172 EXC_ITLB_PV = 0x00a0, /**< `[REEXEC]` Instruction TLB protection violation */
173 EXC_ILLEGAL_INSTR = 0x0180, /**< `[REEXEC]` Illegal instruction */
174 EXC_SLOT_ILLEGAL_INSTR = 0x01a0, /**< `[REEXEC]` Slot illegal instruction */
175 EXC_GENERAL_FPU = 0x0800, /**< `[REEXEC]` General FPU exception */
176 EXC_SLOT_FPU = 0x0820, /**< `[REEXEC]` Slot FPU exception */
177 EXC_DATA_ADDRESS_READ = 0x00e0, /**< `[REEXEC]` Data address (read) */
178 EXC_DATA_ADDRESS_WRITE = 0x0100, /**< `[REEXEC]` Data address (write) */
179 EXC_DTLB_MISS_READ = 0x0040, /**< `[REEXEC]` Data TLB miss (read) */
180 EXC_DTLB_MISS_WRITE = 0x0060, /**< `[REEXEC]` Data TLB miss (write) */
181 EXC_DTLB_PV_READ = 0x00a0, /**< `[REEXEC]` Data TLB protection violation (read) */
182 EXC_DTLB_PV_WRITE = 0x00c0, /**< `[REEXEC]` Data TLB protection violation (write) */
183 EXC_FPU = 0x0120, /**< `[REEXEC]` FPU exception */
184 EXC_INITIAL_PAGE_WRITE = 0x0080, /**< `[REEXEC]` Initial page write exception */
185 EXC_TRAPA = 0x0160, /**< `[POST ]` Unconditional trap (`TRAPA`) */
186 EXC_USER_BREAK_POST = 0x01e0, /**< `[POST ]` User break after instruction */
187 EXC_NMI = 0x01c0, /**< `[POST ]` Nonmaskable interrupt */
188 EXC_IRQ0 = 0x0200, /**< `[POST ]` External IRQ request (level 0) */
189 EXC_IRQ1 = 0x0220, /**< `[POST ]` External IRQ request (level 1) */
190 EXC_IRQ2 = 0x0240, /**< `[POST ]` External IRQ request (level 2) */
191 EXC_IRQ3 = 0x0260, /**< `[POST ]` External IRQ request (level 3) */
192 EXC_IRQ4 = 0x0280, /**< `[POST ]` External IRQ request (level 4) */
193 EXC_IRQ5 = 0x02a0, /**< `[POST ]` External IRQ request (level 5) */
194 EXC_IRQ6 = 0x02c0, /**< `[POST ]` External IRQ request (level 6) */
195 EXC_IRQ7 = 0x02e0, /**< `[POST ]` External IRQ request (level 7) */
196 EXC_IRQ8 = 0x0300, /**< `[POST ]` External IRQ request (level 8) */
197 EXC_IRQ9 = 0x0320, /**< `[POST ]` External IRQ request (level 9) */
198 EXC_IRQA = 0x0340, /**< `[POST ]` External IRQ request (level 10) */
199 EXC_IRQB = 0x0360, /**< `[POST ]` External IRQ request (level 11) */
200 EXC_IRQC = 0x0380, /**< `[POST ]` External IRQ request (level 12) */
201 EXC_IRQD = 0x03a0, /**< `[POST ]` External IRQ request (level 13) */
202 EXC_IRQE = 0x03c0, /**< `[POST ]` External IRQ request (level 14) */
203 EXC_TMU0_TUNI0 = 0x0400, /**< `[POST ]` TMU0 underflow */
204 EXC_TMU1_TUNI1 = 0x0420, /**< `[POST ]` TMU1 underflow */
205 EXC_TMU2_TUNI2 = 0x0440, /**< `[POST ]` TMU2 underflow */
206 EXC_TMU2_TICPI2 = 0x0460, /**< `[UNUSED]` TMU2 input capture */
207 EXC_RTC_ATI = 0x0480, /**< `[UNUSED]` RTC alarm interrupt */
208 EXC_RTC_PRI = 0x04a0, /**< `[UNUSED]` RTC periodic interrupt */
209 EXC_RTC_CUI = 0x04c0, /**< `[UNUSED]` RTC carry interrupt */
210 EXC_SCI_ERI = 0x04e0, /**< `[UNUSED]` SCI Error receive */
211 EXC_SCI_RXI = 0x0500, /**< `[UNUSED]` SCI Receive ready */
212 EXC_SCI_TXI = 0x0520, /**< `[UNUSED]` SCI Transmit ready */
213 EXC_SCI_TEI = 0x0540, /**< `[UNUSED]` SCI Transmit error */
214 EXC_WDT_ITI = 0x0560, /**< `[POST ]` Watchdog timer */
215 EXC_REF_RCMI = 0x0580, /**< `[POST ]` Memory refresh compare-match interrupt */
216 EXC_REF_ROVI = 0x05a0, /**< `[POST ]` Memory refresh counter overflow interrupt */
217 EXC_UDI = 0x0600, /**< `[POST ]` Hitachi UDI */
218 EXC_GPIO_GPIOI = 0x0620, /**< `[POST ]` I/O port interrupt */
219 EXC_DMAC_DMTE0 = 0x0640, /**< `[POST ]` DMAC transfer end (channel 0) */
220 EXC_DMAC_DMTE1 = 0x0660, /**< `[POST ]` DMAC transfer end (channel 1) */
221 EXC_DMAC_DMTE2 = 0x0680, /**< `[POST ]` DMAC transfer end (channel 2) */
222 EXC_DMAC_DMTE3 = 0x06a0, /**< `[POST ]` DMAC transfer end (channel 3) */
223 EXC_DMA_DMAE = 0x06c0, /**< `[POST ]` DMAC address error */
224 EXC_SCIF_ERI = 0x0700, /**< `[POST ]` SCIF Error receive */
225 EXC_SCIF_RXI = 0x0720, /**< `[POST ]` SCIF Receive ready */
226 EXC_SCIF_BRI = 0x0740, /**< `[POST ]` SCIF break */
227 EXC_SCIF_TXI = 0x0760, /**< `[POST ]` SCIF Transmit ready */
228 EXC_DOUBLE_FAULT = 0x0780, /**< `[SOFT ]` Exception happened in an ISR */
229 EXC_UNHANDLED_EXC = 0x07e0, /**< `[SOFT ]` Exception went unhandled */
230 EXC_TRAP = 0x0800 /**< `[TRAP ]` Trap */
231};
232
233#define IRQ_TRAP_CODE(code) (EXC_TRAP + (code))
234
235static inline int arch_irq_inside_int(void) {
236 extern int inside_int;
237
238 return inside_int;
239}
240
241static inline void arch_irq_restore(irq_mask_t old) {
242 __asm__ volatile("ldc %0, sr" : : "r" (old));
243}
244
245static inline irq_mask_t arch_irq_disable(void) {
246 irq_mask_t mask;
247
248 __asm__ volatile("stc sr, %0" : "=r" (mask));
249
250 arch_irq_restore((mask & 0xefffff0f) | 0x000000f0);
251 return mask;
252}
253
254static inline void arch_irq_enable(void) {
255 irq_mask_t mask;
256
257 __asm__ volatile("stc sr, %0" : "=r" (mask));
258
259 arch_irq_restore(mask & 0xefffff0f);
260}
261
262/** \defgroup irq_ctrl Control Flow
263 \brief Methods for managing control flow within an irq_handler.
264
265 This API provides methods for controlling program flow from within an
266 active interrupt handler.
267
268 @{
269*/
270
271void arch_irq_create_context(irq_context_t *context,
272 uintptr_t stack_pointer,
273 uintptr_t routine,
274 const uintptr_t *args);
275
276int arch_irq_set_handler(irq_t code, irq_hdl_t hnd, void *data);
277
278irq_cb_t arch_irq_get_handler(irq_t code);
279
280int arch_irq_set_global_handler(irq_hdl_t hnd, void *data);
281
282irq_cb_t arch_irq_get_global_handler(void);
283
284void arch_irq_set_context(irq_context_t *cxt);
285
286irq_context_t *arch_irq_get_context(void);
287
288/** @} */
289
290/** \brief Minimum/maximum values for IRQ priorities
291
292 A priority of zero means the interrupt is masked.
293 The maximum priority that can be set is 15.
294 */
295#define IRQ_PRIO_MAX 15
296#define IRQ_PRIO_MIN 1
297#define IRQ_PRIO_MASKED 0
298
299/** \brief Interrupt sources
300
301 Interrupt sources at the SH4 level.
302 */
303typedef enum irq_src {
304 IRQ_SRC_RTC,
305 IRQ_SRC_TMU2,
306 IRQ_SRC_TMU1,
307 IRQ_SRC_TMU0,
308 _IRQ_SRC_RESV,
309 IRQ_SRC_SCI1,
310 IRQ_SRC_REF,
311 IRQ_SRC_WDT,
312 IRQ_SRC_HUDI,
313 IRQ_SRC_SCIF,
314 IRQ_SRC_DMAC,
315 IRQ_SRC_GPIO,
316 IRQ_SRC_IRL3,
317 IRQ_SRC_IRL2,
318 IRQ_SRC_IRL1,
319 IRQ_SRC_IRL0,
320} irq_src_t;
321
322/** \brief Set the priority of a given IRQ source
323
324 This function can be used to set the priority of a given IRQ source.
325
326 \param src The interrupt source whose priority should be set
327 \param prio The priority to set, in the range [0..15],
328 0 meaning the IRQs from that source are masked.
329*/
330void irq_set_priority(irq_src_t src, unsigned int prio);
331
332/** \brief Get the priority of a given IRQ source
333
334 This function returns the priority of a given IRQ source.
335
336 \param src The interrupt source whose priority should be set
337 \return The priority of the IRQ source.
338 A value of 0 means the IRQs are masked.
339*/
340unsigned int irq_get_priority(irq_src_t src);
341
342/** @} */
343
344__END_DECLS
345
346#endif /* __ARCH_IRQ_H */
void hnd(const char *file, int line, const char *expr, const char *msg, const char *func)
Definition asserthnd.c:53
static struct @69 data[BARRIER_COUNT]
static float r
Definition bubbles.c:95
static pvr_poly_cxt_t cxt
Definition bubbles.c:28
Various common macros used throughout the codebase.
Timer functionality.
enum irq_exception irq_t
Architecture-specific interrupt exception codes.
Definition irq.h:49
struct irq_context irq_context_t
Architecture-specific structure for holding the processor state.
Definition irq.h:43
uint32_t irq_mask_t
Type representing an interrupt mask state.
Definition irq.h:52
void(* irq_hdl_t)(irq_t code, irq_context_t *context, void *data)
The type of an IRQ handler.
Definition irq.h:60
The type of a full callback of an IRQ handler and userdata.
Definition irq.h:67