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) (irq_t)(EXC_TRAP + (code))
234
235extern int inside_int;
236static inline int arch_irq_inside_int(void) {
237 return inside_int;
238}
239
240static inline void arch_irq_restore(irq_mask_t old) {
241 __asm__ volatile("ldc %0, sr" : : "r" (old));
242}
243
244static inline irq_mask_t arch_irq_disable(void) {
245 irq_mask_t mask;
246
247 __asm__ volatile("stc sr, %0" : "=r" (mask));
248
249 arch_irq_restore((mask & 0xefffff0f) | 0x000000f0);
250 return mask;
251}
252
253static inline void arch_irq_enable(void) {
254 irq_mask_t mask;
255
256 __asm__ volatile("stc sr, %0" : "=r" (mask));
257
258 arch_irq_restore(mask & 0xefffff0f);
259}
260
261/** \defgroup irq_ctrl Control Flow
262 \brief Methods for managing control flow within an irq_handler.
263
264 This API provides methods for controlling program flow from within an
265 active interrupt handler.
266
267 @{
268*/
269
270void arch_irq_create_context(irq_context_t *context,
271 uintptr_t stack_pointer,
272 uintptr_t routine,
273 const uintptr_t *args);
274
275int arch_irq_set_handler(irq_t code, irq_hdl_t hnd, void *data);
276
277irq_cb_t arch_irq_get_handler(irq_t code);
278
279int arch_irq_set_global_handler(irq_hdl_t hnd, void *data);
280
281irq_cb_t arch_irq_get_global_handler(void);
282
283void arch_irq_set_context(irq_context_t *cxt);
284
285irq_context_t *arch_irq_get_context(void);
286
287/** @} */
288
289/** \brief Minimum/maximum values for IRQ priorities
290
291 A priority of zero means the interrupt is masked.
292 The maximum priority that can be set is 15.
293 */
294#define IRQ_PRIO_MAX 15
295#define IRQ_PRIO_MIN 1
296#define IRQ_PRIO_MASKED 0
297
298/** \brief Interrupt sources
299
300 Interrupt sources at the SH4 level.
301 */
302typedef enum irq_src {
303 IRQ_SRC_RTC,
304 IRQ_SRC_TMU2,
305 IRQ_SRC_TMU1,
306 IRQ_SRC_TMU0,
307 _IRQ_SRC_RESV,
308 IRQ_SRC_SCI1,
309 IRQ_SRC_REF,
310 IRQ_SRC_WDT,
311 IRQ_SRC_HUDI,
312 IRQ_SRC_SCIF,
313 IRQ_SRC_DMAC,
314 IRQ_SRC_GPIO,
315 IRQ_SRC_IRL3,
316 IRQ_SRC_IRL2,
317 IRQ_SRC_IRL1,
318 IRQ_SRC_IRL0,
319} irq_src_t;
320
321/** \brief Set the priority of a given IRQ source
322
323 This function can be used to set the priority of a given IRQ source.
324
325 \param src The interrupt source whose priority should be set
326 \param prio The priority to set, in the range [0..15],
327 0 meaning the IRQs from that source are masked.
328*/
329void irq_set_priority(irq_src_t src, unsigned int prio);
330
331/** \brief Get the priority of a given IRQ source
332
333 This function returns the priority of a given IRQ source.
334
335 \param src The interrupt source whose priority should be set
336 \return The priority of the IRQ source.
337 A value of 0 means the IRQs are masked.
338*/
339unsigned int irq_get_priority(irq_src_t src);
340
341/** @} */
342
343__END_DECLS
344
345#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