revert 213 commits (to 56092) from the last month. 10 still need work to resolve...
[AROS.git] / arch / m68k-amiga / kernel / amiga_irq.c
blobb9c4bfe22b2c65a33665e00248b89794e9967035
1 /*
2 copyright © 1995-2017, the aros development team. all rights reserved.
3 $id$
5 desc: m68k-amiga IRQ handling
6 lang: english
7 */
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"
27 /** Interrupts */
28 #define INTENAR 0x1c
29 #define INTREQR 0x1e
30 #define INTENA 0x9a
31 #define INTREQ 0x9c
33 /** DMA **/
34 #define DMACON 0x96
36 /** Display Control **/
37 #define DIWSTRT 0x8e
38 #define DIWSTOP 0x90
40 #define DIWSTRT_NTSC 0x2c81
41 #define DIWSTOP_NTSC 0xf4c1
43 #define DIWSTRT_PAL 0x2c81
44 #define DIWSTOP_PAL 0x2cc1
46 #define DDFSTRT 0x92
47 #define DDFSTOP 0x94
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);
59 *r = val;
62 static inline UWORD custom_r(ULONG reg)
64 volatile UWORD *r = (void *)(0xdff000 + reg);
66 return *r;
70 /* Here's how it's all laid out on the Amiga
71 * M68K Exception
72 * 0 Reset: Initial SP
73 * 1 Reset: Initial PC (NOTE: Really is SysBase!)
74 * 2 Bus Error
75 * 3 Address Error
76 * 4 Illegal Instruction
77 * 5 Divide by Zero
78 * 6 CHK Instruction
79 * 7 TRAPV Instruction
80 * 8 Privileged Instruction
81 * 9 Trace
82 * 10 Line 1010 Emulator
83 * 11 Line 1111 Emulator
84 * 12 -
85 * 13 -
86 * 14 Format Error
87 * 15 Uninitilaized Interrupt Vector
88 * 16 -
89 * ..
90 * 23 -
91 * 24 Spurious Interrupt
92 * 25 Level 1 Interrupt
93 * Paula 0: Serial TX
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
99 * Paula 4: Copper
100 * Paula 5: Vert Blank
101 * Paula 6: Blitter
102 * 28 Level 4 Interrupt
103 * Paula 7: Audio 0
104 * Paula 8: Audio 1
105 * Paula 9: Audio 2
106 * Paula 10: Audio 3
107 * 29 Level 5 Interrupt
108 * Paula 11: Serial RX
109 * Paula 12: Disk Sync
110 * 30 Level 6 Interrupt
111 * Paula 13: External
112 * Paula 14: CIAB & IRQ6
113 * 31 Level 7 Interrupt
114 * Paula 15: NMI
115 * 32 TRAP #0
116 * ..
117 * 47 TRAP #15
118 * 48 -
119 * ..
120 * 63 -
121 * 64 User 1
122 * ..
123 * 255 User 191
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)) \
130 return TRUE; \
131 UWORD mask = intenar & custom_r(INTREQR) & (irq_mask); \
132 do {
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); */ \
144 } while (0); \
145 /* Call Exec/ExitIntr */ \
146 return TRUE;
148 #define DECLARE_TrapCode(handler) \
149 BOOL handler(VOID); \
150 VOID handler##_TrapCode(ULONG Id); \
151 asm ( \
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" \
158 " tst.w %d0\n" \
159 " beq 0f\n" \
160 " jmp Exec_6_ExitIntr\n" \
161 "0:\n" \
162 " movem.l %sp@+,%d0/%d1/%a0/%a1/%a5/%a6\n" \
163 " rte\n" \
164 " .endfunc\n" \
165 ); \
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
183 * 2 - SoftInt
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);
197 PAULA_IRQ_EXIT();
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);
210 PAULA_IRQ_EXIT();
213 BOOL Amiga_Level_3(VOID)
215 /* Paula IRQs 4 - Copper
216 * 5 - Vert Blank
217 * 6 - Blitter
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);
228 PAULA_IRQ_EXIT();
231 BOOL Amiga_Level_4(VOID)
233 /* Paula IRQs 7 - Audio 0
234 * 8 - Audio 1
235 * 9 - Audio 2
236 * 10 - Audio 3
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);
247 PAULA_IRQ_EXIT();
250 BOOL Amiga_Level_5(VOID)
252 /* Paula IRQs 11 - Serial RX
253 * 12 - Disk Sync
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);
262 PAULA_IRQ_EXIT();
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);
277 PAULA_IRQ_EXIT();
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()
291 return FALSE;
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 },
302 { .Id = 0, }
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);
314 /* Enable DMA */
315 custom_w(DMACON, 0x8240);
317 /* Set up Vert. & Horiz. interval
318 * PAL 320x200x4
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 */