forcing device into host mode requires a full config - which we will do in opendevice...
[AROS.git] / arch / m68k-amiga / kernel / amiga_irq.c
blob4f2d3312fe58d21f06f09626118c816628886f63
1 /*
2 copyright © 1995-2010, 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>
14 #include <defines/kernel.h>
16 #include <hardware/intbits.h>
18 #include "kernel_base.h"
19 #include "kernel_intr.h"
20 #include "kernel_syscall.h"
21 #include "kernel_scheduler.h"
23 #include "m68k_exception.h"
24 #include "amiga_irq.h"
26 #include "exec_intern.h"
28 /** Interrupts */
29 #define INTENAR 0x1c
30 #define INTREQR 0x1e
31 #define INTENA 0x9a
32 #define INTREQ 0x9c
34 /** DMA **/
35 #define DMACON 0x96
37 /** Display Control **/
38 #define DIWSTRT 0x8e
39 #define DIWSTOP 0x90
41 #define DIWSTRT_NTSC 0x2c81
42 #define DIWSTOP_NTSC 0xf4c1
44 #define DIWSTRT_PAL 0x2c81
45 #define DIWSTOP_PAL 0x2cc1
47 #define DDFSTRT 0x92
48 #define DDFSTOP 0x94
50 #define DDFSTRT_LOW 0x0038
51 #define DDFSTOP_LOW 0x00d0
53 #define DDFSTRT_HIGH 0x003c
54 #define DDFSTOP_HIGH 0x00d4
56 static inline void custom_w(ULONG reg, UWORD val)
58 volatile UWORD *r = (void *)(0xdff000 + reg);
60 *r = val;
63 static inline UWORD custom_r(ULONG reg)
65 volatile UWORD *r = (void *)(0xdff000 + reg);
67 return *r;
71 /* Here's how it's all laid out on the Amiga
72 * M68K Exception
73 * 0 Reset: Initial SP
74 * 1 Reset: Initial PC (NOTE: Really is SysBase!)
75 * 2 Bus Error
76 * 3 Address Error
77 * 4 Illegal Instruction
78 * 5 Divide by Zero
79 * 6 CHK Instruction
80 * 7 TRAPV Instruction
81 * 8 Privileged Instruction
82 * 9 Trace
83 * 10 Line 1010 Emulator
84 * 11 Line 1111 Emulator
85 * 12 -
86 * 13 -
87 * 14 Format Error
88 * 15 Uninitilaized Interrupt Vector
89 * 16 -
90 * ..
91 * 23 -
92 * 24 Spurious Interrupt
93 * 25 Level 1 Interrupt
94 * Paula 0: Serial TX
95 * Paula 1: Disk DMA done
96 * Paula 2: Software Int
97 * 26 Level 2 Interrupt
98 * Paula 3: CIAA & IRQ2
99 * 27 Level 3 Interrupt
100 * Paula 4: Copper
101 * Paula 5: Vert Blank
102 * Paula 6: Blitter
103 * 28 Level 4 Interrupt
104 * Paula 7: Audio 0
105 * Paula 8: Audio 1
106 * Paula 9: Audio 2
107 * Paula 10: Audio 3
108 * 29 Level 5 Interrupt
109 * Paula 11: Serial RX
110 * Paula 12: Disk Sync
111 * 30 Level 6 Interrupt
112 * Paula 13: External
113 * Paula 14: CIAB & IRQ6
114 * 31 Level 7 Interrupt
115 * Paula 15: NMI
116 * 32 TRAP #0
117 * ..
118 * 47 TRAP #15
119 * 48 -
120 * ..
121 * 63 -
122 * 64 User 1
123 * ..
124 * 255 User 191
127 #define PAULA_IRQ_CHECK(valid_mask) \
128 const UWORD irq_mask = valid_mask; \
129 UWORD intenar = custom_r(INTENAR); \
130 if (!(intenar & INTF_INTEN)) \
131 return TRUE; \
132 UWORD mask = intenar & custom_r(INTREQR) & (irq_mask); \
133 do {
135 #define PAULA_IRQ_ACK(clear_mask) \
136 custom_w(INTREQ, mask & (clear_mask));
138 #define PAULA_IRQ_HANDLE(irq) \
139 if ((mask) & (1 << (irq))) { \
140 core_Cause(irq, mask); \
143 #define PAULA_IRQ_EXIT() \
144 /* mask = custom_r(INTENAR) & custom_r(INTREQR) & (irq_mask); */ \
145 } while (0); \
146 /* Call Exec/ExitIntr */ \
147 return TRUE;
149 #define DECLARE_TrapCode(handler) \
150 BOOL handler(VOID); \
151 VOID handler##_TrapCode(ULONG Id); \
152 asm ( \
153 " .global " #handler "_TrapCode\n" \
154 " .func " #handler "_TrapCode\n" \
155 #handler "_TrapCode:\n" \
156 " addq.l #4,%sp\n" /* Drop the ID */ \
157 " movem.l %d0/%d1/%a0/%a1/%a5/%a6,%sp@-\n" \
158 " jsr " #handler "\n" \
159 " tst.w %d0\n" \
160 " beq 0f\n" \
161 " jmp Exec_6_ExitIntr\n" \
162 "0:\n" \
163 " movem.l %sp@+,%d0/%d1/%a0/%a1/%a5/%a6\n" \
164 " rte\n" \
165 " .endfunc\n" \
166 ); \
168 /* AOS interrupt handlers will clear INTREQ before executing interrupt code,
169 * servers will clear INTREQ after whole server chain has been executed.
172 DECLARE_TrapCode(Amiga_Level_1);
173 DECLARE_TrapCode(Amiga_Level_2);
174 DECLARE_TrapCode(Amiga_Level_3);
175 DECLARE_TrapCode(Amiga_Level_4);
176 DECLARE_TrapCode(Amiga_Level_5);
177 DECLARE_TrapCode(Amiga_Level_6);
178 DECLARE_TrapCode(Amiga_Level_7);
180 BOOL Amiga_Level_1(VOID)
182 /* Paula IRQs 0 - Serial port TX done
183 * 1 - Disk DMA finished
184 * 2 - SoftInt
187 PAULA_IRQ_CHECK(INTF_SOFTINT | INTF_DSKBLK | INTF_TBE);
189 /* SOFTINT is cleared by SOFTINT handler, we can't clear it
190 * here anymore because SOFTINT handler may call Cause() internally
192 PAULA_IRQ_ACK(INTF_DSKBLK | INTF_TBE);
194 PAULA_IRQ_HANDLE(INTB_TBE);
195 PAULA_IRQ_HANDLE(INTB_DSKBLK);
196 PAULA_IRQ_HANDLE(INTB_SOFTINT);
198 PAULA_IRQ_EXIT();
201 BOOL Amiga_Level_2(VOID)
203 /* Paula IRQs 3 - CIA-A
205 PAULA_IRQ_CHECK(INTF_PORTS);
207 PAULA_IRQ_HANDLE(INTB_PORTS);
209 PAULA_IRQ_ACK(INTF_PORTS);
211 PAULA_IRQ_EXIT();
214 BOOL Amiga_Level_3(VOID)
216 /* Paula IRQs 4 - Copper
217 * 5 - Vert Blank
218 * 6 - Blitter
220 PAULA_IRQ_CHECK(INTF_COPER | INTF_VERTB | INTF_BLIT);
222 PAULA_IRQ_HANDLE(INTB_COPER);
223 PAULA_IRQ_HANDLE(INTB_VERTB);
225 PAULA_IRQ_ACK(INTF_COPER | INTF_VERTB | INTF_BLIT);
227 PAULA_IRQ_HANDLE(INTB_BLIT);
229 PAULA_IRQ_EXIT();
232 BOOL Amiga_Level_4(VOID)
234 /* Paula IRQs 7 - Audio 0
235 * 8 - Audio 1
236 * 9 - Audio 2
237 * 10 - Audio 3
239 PAULA_IRQ_CHECK(INTF_AUD0 | INTF_AUD1 | INTF_AUD2 | INTF_AUD3);
241 PAULA_IRQ_ACK(INTF_AUD0 | INTF_AUD1 | INTF_AUD2 | INTF_AUD3);
243 PAULA_IRQ_HANDLE(INTB_AUD0);
244 PAULA_IRQ_HANDLE(INTB_AUD1);
245 PAULA_IRQ_HANDLE(INTB_AUD2);
246 PAULA_IRQ_HANDLE(INTB_AUD3);
248 PAULA_IRQ_EXIT();
251 BOOL Amiga_Level_5(VOID)
253 /* Paula IRQs 11 - Serial RX
254 * 12 - Disk Sync
256 PAULA_IRQ_CHECK(INTF_RBF | INTF_DSKSYNC);
258 PAULA_IRQ_ACK(INTF_RBF | INTF_DSKSYNC);
260 PAULA_IRQ_HANDLE(INTB_RBF);
261 PAULA_IRQ_HANDLE(INTB_DSKSYNC);
263 PAULA_IRQ_EXIT();
266 BOOL Amiga_Level_6(VOID)
268 /* Paula IRQ 13 - CIA-B & IRQ6
269 * 14 - INTEN (manually setting INTEN bit in INTREQ triggers it)
271 PAULA_IRQ_CHECK(INTF_EXTER | INTF_INTEN);
273 PAULA_IRQ_HANDLE(INTB_EXTER);
274 PAULA_IRQ_HANDLE(INTB_INTEN);
276 PAULA_IRQ_ACK(INTF_EXTER);
278 PAULA_IRQ_EXIT();
281 BOOL Amiga_Level_7(VOID)
283 /* NMI - no way around it.
285 const UWORD mask = (1 << 15);
287 PAULA_IRQ_HANDLE(15);
289 /* Don't reschedule on the way out - so don't
290 * call PAULA_IRQ_EXIT()
292 return FALSE;
295 const struct M68KException AmigaExceptionTable[] = {
296 { .Id = 25, .Handler = Amiga_Level_1_TrapCode },
297 { .Id = 26, .Handler = Amiga_Level_2_TrapCode },
298 { .Id = 27, .Handler = Amiga_Level_3_TrapCode },
299 { .Id = 28, .Handler = Amiga_Level_4_TrapCode },
300 { .Id = 29, .Handler = Amiga_Level_5_TrapCode },
301 { .Id = 30, .Handler = Amiga_Level_6_TrapCode },
302 { .Id = 31, .Handler = Amiga_Level_7_TrapCode },
303 { .Id = 0, }
306 void AmigaIRQInit(struct ExecBase *SysBase)
308 /* Disable all interrupts */
309 custom_w(INTENA, 0x7fff);
310 /* Clear any requests */
311 custom_w(INTREQ, 0x7fff);
313 M68KExceptionInit(AmigaExceptionTable, SysBase);
315 /* Enable DMA */
316 custom_w(DMACON, 0x8240);
318 /* Set up Vert. & Horiz. interval
319 * PAL 320x200x4
321 custom_w(DIWSTRT, DIWSTRT_PAL);
322 custom_w(DIWSTOP, DIWSTOP_PAL);
323 custom_w(DDFSTRT, DDFSTRT_LOW);
324 custom_w(DDFSTOP, DDFSTOP_LOW);
326 /* Enable Vertical Blank and SoftInt */
327 custom_w(INTENA, INTF_SETCLR | INTF_VERTB | INTF_SOFTINT);
329 /* IRQs will be enabled by the first Enable() in Exec's init */