2 copyright © 1995-2010, 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>
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"
37 /** Display Control **/
41 #define DIWSTRT_NTSC 0x2c81
42 #define DIWSTOP_NTSC 0xf4c1
44 #define DIWSTRT_PAL 0x2c81
45 #define DIWSTOP_PAL 0x2cc1
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
);
63 static inline UWORD
custom_r(ULONG reg
)
65 volatile UWORD
*r
= (void *)(0xdff000 + reg
);
71 /* Here's how it's all laid out on the Amiga
74 * 1 Reset: Initial PC (NOTE: Really is SysBase!)
77 * 4 Illegal Instruction
81 * 8 Privileged Instruction
83 * 10 Line 1010 Emulator
84 * 11 Line 1111 Emulator
88 * 15 Uninitilaized Interrupt Vector
92 * 24 Spurious Interrupt
93 * 25 Level 1 Interrupt
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
101 * Paula 5: Vert Blank
103 * 28 Level 4 Interrupt
108 * 29 Level 5 Interrupt
109 * Paula 11: Serial RX
110 * Paula 12: Disk Sync
111 * 30 Level 6 Interrupt
113 * Paula 14: CIAB & IRQ6
114 * 31 Level 7 Interrupt
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)) \
132 UWORD mask = intenar & custom_r(INTREQR) & (irq_mask); \
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); */ \
146 /* Call Exec/ExitIntr */ \
149 #define DECLARE_TrapCode(handler) \
150 BOOL handler(VOID); \
151 VOID handler##_TrapCode(ULONG Id); \
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" \
161 " jmp Exec_6_ExitIntr\n" \
163 " movem.l %sp@+,%d0/%d1/%a0/%a1/%a5/%a6\n" \
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
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
);
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
);
214 BOOL
Amiga_Level_3(VOID
)
216 /* Paula IRQs 4 - Copper
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
);
232 BOOL
Amiga_Level_4(VOID
)
234 /* Paula IRQs 7 - Audio 0
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
);
251 BOOL
Amiga_Level_5(VOID
)
253 /* Paula IRQs 11 - Serial RX
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
);
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
);
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()
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
},
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
);
316 custom_w(DMACON
, 0x8240);
318 /* Set up Vert. & Horiz. interval
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 */