2 copyright © 1995-2017, the aros development team. all rights reserved.
5 desc: m68k-amiga IRQ handling
9 #include <aros/kernel.h>
10 #include <aros/asmcall.h>
12 #include <exec/resident.h>
13 #include <exec/execbase.h>
15 #include <hardware/intbits.h>
17 #include "kernel_base.h"
18 #include "kernel_intr.h"
19 #include "kernel_syscall.h"
20 #include "kernel_scheduler.h"
22 #include "m68k_exception.h"
23 #include "amiga_irq.h"
25 #include "exec_intern.h"
36 /** Display Control **/
40 #define DIWSTRT_NTSC 0x2c81
41 #define DIWSTOP_NTSC 0xf4c1
43 #define DIWSTRT_PAL 0x2c81
44 #define DIWSTOP_PAL 0x2cc1
49 #define DDFSTRT_LOW 0x0038
50 #define DDFSTOP_LOW 0x00d0
52 #define DDFSTRT_HIGH 0x003c
53 #define DDFSTOP_HIGH 0x00d4
55 static inline void custom_w(ULONG reg
, UWORD val
)
57 volatile UWORD
*r
= (void *)(0xdff000 + reg
);
62 static inline UWORD
custom_r(ULONG reg
)
64 volatile UWORD
*r
= (void *)(0xdff000 + reg
);
70 /* Here's how it's all laid out on the Amiga
73 * 1 Reset: Initial PC (NOTE: Really is SysBase!)
76 * 4 Illegal Instruction
80 * 8 Privileged Instruction
82 * 10 Line 1010 Emulator
83 * 11 Line 1111 Emulator
87 * 15 Uninitilaized Interrupt Vector
91 * 24 Spurious Interrupt
92 * 25 Level 1 Interrupt
94 * Paula 1: Disk DMA done
95 * Paula 2: Software Int
96 * 26 Level 2 Interrupt
97 * Paula 3: CIAA & IRQ2
98 * 27 Level 3 Interrupt
100 * Paula 5: Vert Blank
102 * 28 Level 4 Interrupt
107 * 29 Level 5 Interrupt
108 * Paula 11: Serial RX
109 * Paula 12: Disk Sync
110 * 30 Level 6 Interrupt
112 * Paula 14: CIAB & IRQ6
113 * 31 Level 7 Interrupt
126 #define PAULA_IRQ_CHECK(valid_mask) \
127 const UWORD irq_mask = valid_mask; \
128 UWORD intenar = custom_r(INTENAR); \
129 if (!(intenar & INTF_INTEN)) \
131 UWORD mask = intenar & custom_r(INTREQR) & (irq_mask); \
134 #define PAULA_IRQ_ACK(clear_mask) \
135 custom_w(INTREQ, mask & (clear_mask));
137 #define PAULA_IRQ_HANDLE(irq) \
138 if ((mask) & (1 << (irq))) { \
139 core_Cause(irq, mask); \
142 #define PAULA_IRQ_EXIT() \
143 /* mask = custom_r(INTENAR) & custom_r(INTREQR) & (irq_mask); */ \
145 /* Call Exec/ExitIntr */ \
148 #define DECLARE_TrapCode(handler) \
149 BOOL handler(VOID); \
150 VOID handler##_TrapCode(ULONG Id); \
152 " .global " #handler "_TrapCode\n" \
153 " .func " #handler "_TrapCode\n" \
154 #handler "_TrapCode:\n" \
155 " addq.l #4,%sp\n" /* Drop the ID */ \
156 " movem.l %d0/%d1/%a0/%a1/%a5/%a6,%sp@-\n" \
157 " jsr " #handler "\n" \
160 " jmp Exec_6_ExitIntr\n" \
162 " movem.l %sp@+,%d0/%d1/%a0/%a1/%a5/%a6\n" \
167 /* AOS interrupt handlers will clear INTREQ before executing interrupt code,
168 * servers will clear INTREQ after whole server chain has been executed.
171 DECLARE_TrapCode(Amiga_Level_1
);
172 DECLARE_TrapCode(Amiga_Level_2
);
173 DECLARE_TrapCode(Amiga_Level_3
);
174 DECLARE_TrapCode(Amiga_Level_4
);
175 DECLARE_TrapCode(Amiga_Level_5
);
176 DECLARE_TrapCode(Amiga_Level_6
);
177 DECLARE_TrapCode(Amiga_Level_7
);
179 BOOL
Amiga_Level_1(VOID
)
181 /* Paula IRQs 0 - Serial port TX done
182 * 1 - Disk DMA finished
186 PAULA_IRQ_CHECK(INTF_SOFTINT
| INTF_DSKBLK
| INTF_TBE
);
188 /* SOFTINT is cleared by SOFTINT handler, we can't clear it
189 * here anymore because SOFTINT handler may call Cause() internally
191 PAULA_IRQ_ACK(INTF_DSKBLK
| INTF_TBE
);
193 PAULA_IRQ_HANDLE(INTB_TBE
);
194 PAULA_IRQ_HANDLE(INTB_DSKBLK
);
195 PAULA_IRQ_HANDLE(INTB_SOFTINT
);
200 BOOL
Amiga_Level_2(VOID
)
202 /* Paula IRQs 3 - CIA-A
204 PAULA_IRQ_CHECK(INTF_PORTS
);
206 PAULA_IRQ_HANDLE(INTB_PORTS
);
208 PAULA_IRQ_ACK(INTF_PORTS
);
213 BOOL
Amiga_Level_3(VOID
)
215 /* Paula IRQs 4 - Copper
219 PAULA_IRQ_CHECK(INTF_COPER
| INTF_VERTB
| INTF_BLIT
);
221 PAULA_IRQ_HANDLE(INTB_COPER
);
222 PAULA_IRQ_HANDLE(INTB_VERTB
);
224 PAULA_IRQ_ACK(INTF_COPER
| INTF_VERTB
| INTF_BLIT
);
226 PAULA_IRQ_HANDLE(INTB_BLIT
);
231 BOOL
Amiga_Level_4(VOID
)
233 /* Paula IRQs 7 - Audio 0
238 PAULA_IRQ_CHECK(INTF_AUD0
| INTF_AUD1
| INTF_AUD2
| INTF_AUD3
);
240 PAULA_IRQ_ACK(INTF_AUD0
| INTF_AUD1
| INTF_AUD2
| INTF_AUD3
);
242 PAULA_IRQ_HANDLE(INTB_AUD0
);
243 PAULA_IRQ_HANDLE(INTB_AUD1
);
244 PAULA_IRQ_HANDLE(INTB_AUD2
);
245 PAULA_IRQ_HANDLE(INTB_AUD3
);
250 BOOL
Amiga_Level_5(VOID
)
252 /* Paula IRQs 11 - Serial RX
255 PAULA_IRQ_CHECK(INTF_RBF
| INTF_DSKSYNC
);
257 PAULA_IRQ_ACK(INTF_RBF
| INTF_DSKSYNC
);
259 PAULA_IRQ_HANDLE(INTB_RBF
);
260 PAULA_IRQ_HANDLE(INTB_DSKSYNC
);
265 BOOL
Amiga_Level_6(VOID
)
267 /* Paula IRQ 13 - CIA-B & IRQ6
268 * 14 - INTEN (manually setting INTEN bit in INTREQ triggers it)
270 PAULA_IRQ_CHECK(INTF_EXTER
| INTF_INTEN
);
272 PAULA_IRQ_HANDLE(INTB_EXTER
);
273 PAULA_IRQ_HANDLE(INTB_INTEN
);
275 PAULA_IRQ_ACK(INTF_EXTER
);
280 BOOL
Amiga_Level_7(VOID
)
282 /* NMI - no way around it.
284 const UWORD mask
= (1 << 15);
286 PAULA_IRQ_HANDLE(15);
288 /* Don't reschedule on the way out - so don't
289 * call PAULA_IRQ_EXIT()
294 const struct M68KException AmigaExceptionTable
[] = {
295 { .Id
= 25, .Handler
= Amiga_Level_1_TrapCode
},
296 { .Id
= 26, .Handler
= Amiga_Level_2_TrapCode
},
297 { .Id
= 27, .Handler
= Amiga_Level_3_TrapCode
},
298 { .Id
= 28, .Handler
= Amiga_Level_4_TrapCode
},
299 { .Id
= 29, .Handler
= Amiga_Level_5_TrapCode
},
300 { .Id
= 30, .Handler
= Amiga_Level_6_TrapCode
},
301 { .Id
= 31, .Handler
= Amiga_Level_7_TrapCode
},
305 void AmigaIRQInit(struct ExecBase
*SysBase
)
307 /* Disable all interrupts */
308 custom_w(INTENA
, 0x7fff);
309 /* Clear any requests */
310 custom_w(INTREQ
, 0x7fff);
312 M68KExceptionInit(AmigaExceptionTable
, SysBase
);
315 custom_w(DMACON
, 0x8240);
317 /* Set up Vert. & Horiz. interval
320 custom_w(DIWSTRT
, DIWSTRT_PAL
);
321 custom_w(DIWSTOP
, DIWSTOP_PAL
);
322 custom_w(DDFSTRT
, DDFSTRT_LOW
);
323 custom_w(DDFSTOP
, DDFSTOP_LOW
);
325 /* Enable Vertical Blank and SoftInt */
326 custom_w(INTENA
, INTF_SETCLR
| INTF_VERTB
| INTF_SOFTINT
);
328 /* IRQs will be enabled by the first Enable() in Exec's init */