mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
exec_os: enrich all stubs to bootcamp-quality reference articles
Complete rewrite of 14 exec_os articles from stubs to comprehensive deep-dive technical references with architecture diagrams, pitfalls, and best practices. New: multitasking.md (scheduler, IPC, memory safety, real-world scenarios) Enriched: exec_base, tasks_processes, library_system, library_vectors, interrupts, exceptions_traps, memory_management, message_ports, signals, semaphores, io_requests, lists_nodes, resident_modules Updated indexes: 06_exec_os/README.md, root README.md
This commit is contained in:
parent
4d136b0672
commit
59929047d4
16 changed files with 4463 additions and 678 deletions
|
|
@ -4,123 +4,401 @@
|
|||
|
||||
## Overview
|
||||
|
||||
AmigaOS supports 7 hardware interrupt levels (68k IPL0–IPL6) plus a software interrupt mechanism. Custom chip interrupts are filtered through the `INTENA` / `INTREQ` registers; CIA-generated interrupts arrive on level 2 (CIA-A) and level 6 (CIA-B).
|
||||
AmigaOS supports 7 hardware interrupt levels (68k IPL0–IPL6) plus a software interrupt mechanism. Custom chip interrupts are filtered through the `INTENA` / `INTREQ` registers; CIA-generated interrupts arrive on level 2 (CIA-A) and level 6 (CIA-B). The interrupt system is the foundation of all real-time behavior — audio DMA, vertical blank timing, keyboard input, and the scheduler itself all depend on it.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Hardware Sources"
|
||||
SER["Serial Port"]
|
||||
DSK["Disk Controller"]
|
||||
KBD["Keyboard (CIA-A)"]
|
||||
TMR["CIA Timers"]
|
||||
COP["Copper"]
|
||||
VBL["Vertical Blank"]
|
||||
BLT["Blitter"]
|
||||
AUD["Audio DMA"]
|
||||
EXT["External (CIA-B)"]
|
||||
end
|
||||
|
||||
subgraph "Custom Chips"
|
||||
INTREQ["INTREQ<br/>($DFF09C)"]
|
||||
INTENA["INTENA<br/>($DFF09A)"]
|
||||
end
|
||||
|
||||
subgraph "68k CPU"
|
||||
IPL["IPL0-IPL6<br/>(priority encoder)"]
|
||||
VEC["Exception Vector<br/>($64–$78)"]
|
||||
ISR["Exec Interrupt<br/>Dispatcher"]
|
||||
end
|
||||
|
||||
subgraph "Exec"
|
||||
CHAIN["Interrupt Server<br/>Chain (per level)"]
|
||||
SOFT["Software Interrupt<br/>Queue"]
|
||||
end
|
||||
|
||||
SER --> INTREQ
|
||||
DSK --> INTREQ
|
||||
COP --> INTREQ
|
||||
VBL --> INTREQ
|
||||
BLT --> INTREQ
|
||||
AUD --> INTREQ
|
||||
KBD --> INTREQ
|
||||
EXT --> INTREQ
|
||||
|
||||
INTREQ --> INTENA
|
||||
INTENA --> IPL
|
||||
IPL --> VEC
|
||||
VEC --> ISR
|
||||
ISR --> CHAIN
|
||||
CHAIN --> SOFT
|
||||
|
||||
style INTREQ fill:#fff3e0,stroke:#ff9800,color:#333
|
||||
style INTENA fill:#fff3e0,stroke:#ff9800,color:#333
|
||||
style ISR fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interrupt Priority Levels
|
||||
|
||||
| IPL | Source | AmigaOS Use |
|
||||
|---|---|---|
|
||||
| 1 | TBE, DSKBLK, SOFTINT | Software interrupts (`SoftInt`) |
|
||||
| 2 | PORTS (CIA-A) | Keyboard, timer, parallel, floppy motor |
|
||||
| 3 | COPER, VERTB, BLIT | Copper, vertical blank, blitter |
|
||||
| 4 | AUD0–AUD3 | Audio DMA completion |
|
||||
| 5 | RBF, DSKSYNC | Serial receive, disk sync |
|
||||
| 6 | EXTER (CIA-B) | External interrupts, CIA-B timers, TOD |
|
||||
| 7 | NMI | Non-maskable (unused on stock Amiga) |
|
||||
| IPL | Source Bits | AmigaOS Use | Typical Latency |
|
||||
|---|---|---|---|
|
||||
| 1 | TBE, DSKBLK, SOFTINT | Software interrupts, serial TX, disk DMA complete | ~10 µs |
|
||||
| 2 | PORTS (CIA-A) | Keyboard, CIA-A timers, parallel port, floppy index | ~15 µs |
|
||||
| 3 | COPER, VERTB, BLIT | Copper, vertical blank, blitter done | ~10 µs |
|
||||
| 4 | AUD0–AUD3 | Audio channel DMA completion | ~10 µs |
|
||||
| 5 | RBF, DSKSYNC | Serial receive, disk sync word | ~8 µs |
|
||||
| 6 | EXTER (CIA-B) | CIA-B timers, external interrupts, TOD alarm | ~8 µs |
|
||||
| 7 | NMI | Non-maskable (unused on stock Amiga hardware) | — |
|
||||
|
||||
Higher IPL = higher priority. A level 6 interrupt can preempt level 1–5 handlers. The CPU's SR (Status Register) mask bits determine which levels are currently enabled.
|
||||
|
||||
### Interrupt Sources per Level
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "Level 1"
|
||||
L1A["TBE<br/>Serial TX"]
|
||||
L1B["DSKBLK<br/>Disk DMA"]
|
||||
L1C["SOFTINT<br/>Software"]
|
||||
end
|
||||
|
||||
subgraph "Level 2"
|
||||
L2["PORTS<br/>CIA-A"]
|
||||
end
|
||||
|
||||
subgraph "Level 3"
|
||||
L3A["COPER<br/>Copper"]
|
||||
L3B["VERTB<br/>VBlank"]
|
||||
L3C["BLIT<br/>Blitter"]
|
||||
end
|
||||
|
||||
subgraph "Level 4"
|
||||
L4A["AUD0"]
|
||||
L4B["AUD1"]
|
||||
L4C["AUD2"]
|
||||
L4D["AUD3"]
|
||||
end
|
||||
|
||||
subgraph "Level 5"
|
||||
L5A["RBF<br/>Serial RX"]
|
||||
L5B["DSKSYNC<br/>Disk sync"]
|
||||
end
|
||||
|
||||
subgraph "Level 6"
|
||||
L6["EXTER<br/>CIA-B"]
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Chip Interrupt Registers
|
||||
|
||||
| Register | Address | Description |
|
||||
|---|---|---|
|
||||
| `INTENAR` | `$DFF01C` | Interrupt enable status (read) |
|
||||
| `INTENA` | `$DFF09A` | Interrupt enable set/clear (write) |
|
||||
| `INTREQR` | `$DFF01E` | Interrupt request status (read) |
|
||||
| `INTREQ` | `$DFF09C` | Interrupt request clear/set (write) |
|
||||
| Register | Address | R/W | Description |
|
||||
|---|---|---|---|
|
||||
| `INTENAR` | `$DFF01C` | R | Interrupt enable status (read) |
|
||||
| `INTENA` | `$DFF09A` | W | Interrupt enable set/clear (write) |
|
||||
| `INTREQR` | `$DFF01E` | R | Interrupt request status (read) |
|
||||
| `INTREQ` | `$DFF09C` | W | Interrupt request clear/set (write) |
|
||||
|
||||
### INTENA / INTREQ Bit Map
|
||||
|
||||
| Bit | Constant | Source |
|
||||
|---|---|---|
|
||||
| 0 | `INTF_TBE` | Serial transmit buffer empty |
|
||||
| 1 | `INTF_DSKBLK` | Disk DMA block complete |
|
||||
| 2 | `INTF_SOFTINT` | Software interrupt |
|
||||
| 3 | `INTF_PORTS` | CIA-A interrupt (level 2) |
|
||||
| 4 | `INTF_COPER` | Copper interrupt |
|
||||
| 5 | `INTF_VERTB` | Vertical blank |
|
||||
| 6 | `INTF_BLIT` | Blitter interrupt |
|
||||
| 7 | `INTF_AUD0` | Audio channel 0 |
|
||||
| 8 | `INTF_AUD1` | Audio channel 1 |
|
||||
| 9 | `INTF_AUD2` | Audio channel 2 |
|
||||
| 10 | `INTF_AUD3` | Audio channel 3 |
|
||||
| 11 | `INTF_RBF` | Serial receive buffer full |
|
||||
| 12 | `INTF_DSKSYNC` | Disk sync word match |
|
||||
| 13 | `INTF_EXTER` | CIA-B / external interrupt |
|
||||
| 14 | `INTF_INTEN` | Master interrupt enable bit |
|
||||
| Bit | Constant | Level | Source |
|
||||
|---|---|---|---|
|
||||
| 0 | `INTF_TBE` | 1 | Serial transmit buffer empty |
|
||||
| 1 | `INTF_DSKBLK` | 1 | Disk DMA block complete |
|
||||
| 2 | `INTF_SOFTINT` | 1 | Software interrupt |
|
||||
| 3 | `INTF_PORTS` | 2 | CIA-A interrupt (keyboard, timers) |
|
||||
| 4 | `INTF_COPER` | 3 | Copper interrupt |
|
||||
| 5 | `INTF_VERTB` | 3 | Vertical blank |
|
||||
| 6 | `INTF_BLIT` | 3 | Blitter finished |
|
||||
| 7 | `INTF_AUD0` | 4 | Audio channel 0 DMA done |
|
||||
| 8 | `INTF_AUD1` | 4 | Audio channel 1 DMA done |
|
||||
| 9 | `INTF_AUD2` | 4 | Audio channel 2 DMA done |
|
||||
| 10 | `INTF_AUD3` | 4 | Audio channel 3 DMA done |
|
||||
| 11 | `INTF_RBF` | 5 | Serial receive buffer full |
|
||||
| 12 | `INTF_DSKSYNC` | 5 | Disk sync word match |
|
||||
| 13 | `INTF_EXTER` | 6 | CIA-B / external interrupt |
|
||||
| 14 | `INTF_INTEN` | — | **Master interrupt enable** |
|
||||
| 15 | `INTF_SETCLR` | — | Set/Clear control bit (write only) |
|
||||
|
||||
To enable vertical blank: write `$C005` to `INTENA` (bit 14 set = enable, bit 5 = VERTB).
|
||||
To clear vertical blank request: write `$0020` to `INTREQ`.
|
||||
### Enabling and Clearing Interrupts
|
||||
|
||||
```c
|
||||
/* Enable vertical blank interrupt:
|
||||
Bit 15 (SET) | Bit 14 (INTEN) | Bit 5 (VERTB) = $C020 */
|
||||
custom.intena = INTF_SETCLR | INTF_INTEN | INTF_VERTB;
|
||||
|
||||
/* Disable vertical blank (clear bit 5): */
|
||||
custom.intena = INTF_VERTB; /* Bit 15 clear = CLEAR mode */
|
||||
|
||||
/* Acknowledge (clear) a vertical blank request: */
|
||||
custom.intreq = INTF_VERTB;
|
||||
```
|
||||
|
||||
> **Important**: You must write `INTF_SETCLR` (bit 15) to SET bits. Without it, you CLEAR them. This is a common source of bugs.
|
||||
|
||||
---
|
||||
|
||||
## Adding an Interrupt Server
|
||||
## Exec Interrupt Dispatch
|
||||
|
||||
### Server Chain vs Direct Handler
|
||||
|
||||
Exec provides two models for handling interrupts:
|
||||
|
||||
| Model | Function | Use Case |
|
||||
|---|---|---|
|
||||
| **Server chain** | `AddIntServer()` / `RemIntServer()` | Shared interrupts (multiple handlers per level) |
|
||||
| **Direct handler** | `SetIntVector()` | Exclusive interrupt ownership |
|
||||
|
||||
For levels with multiple sources (VBL, PORTS), use the **server chain**. Each handler in the chain checks if the interrupt is for it and returns D0=0 (not mine) or D0≠0 (handled).
|
||||
|
||||
### Adding an Interrupt Server
|
||||
|
||||
```c
|
||||
struct Interrupt myVBL = {
|
||||
{ NULL, NULL, NT_INTERRUPT, 0, "My VBL" },
|
||||
NULL, /* is_Data (passed to handler) */
|
||||
myVBLHandler /* is_Code */
|
||||
};
|
||||
/* Vertical blank interrupt server */
|
||||
struct Interrupt myVBL;
|
||||
|
||||
AddIntServer(INTB_VERTB, &myVBL); /* INTB_VERTB = 5 */
|
||||
/* ... run ... */
|
||||
RemIntServer(INTB_VERTB, &myVBL); /* always remove before exit */
|
||||
myVBL.is_Node.ln_Type = NT_INTERRUPT;
|
||||
myVBL.is_Node.ln_Pri = 0; /* Priority within this level */
|
||||
myVBL.is_Node.ln_Name = "MyApp VBL";
|
||||
myVBL.is_Data = myDataPtr; /* Passed in A1 */
|
||||
myVBL.is_Code = myVBLFunc; /* Handler address */
|
||||
|
||||
AddIntServer(INTB_VERTB, &myVBL); /* INTB_VERTB = 5 */
|
||||
|
||||
/* ... application runs ... */
|
||||
|
||||
RemIntServer(INTB_VERTB, &myVBL); /* MUST remove before exit! */
|
||||
```
|
||||
|
||||
### Interrupt Handler Rules
|
||||
### Interrupt Handler Implementation
|
||||
|
||||
- Handler is called at interrupt level — **no OS calls that Wait()**
|
||||
- D0–D1, A0–A1 may be trashed; all others preserved
|
||||
- Return D0 = 0 if you did not handle it (pass to next server)
|
||||
- Return D0 ≠ 0 if you handled it (stop server chain)
|
||||
```c
|
||||
/* C handler — called at interrupt level */
|
||||
ULONG __saveds __interrupt MyVBLHandler(
|
||||
struct Interrupt *irq __asm("a1")) /* is_Data in A1 */
|
||||
{
|
||||
struct MyData *data = (struct MyData *)irq;
|
||||
|
||||
/* Do fast work only */
|
||||
data->frameCount++;
|
||||
|
||||
if (data->needUpdate)
|
||||
{
|
||||
data->needUpdate = FALSE;
|
||||
Signal(data->mainTask, data->updateSig); /* Wake main task */
|
||||
}
|
||||
|
||||
return 1; /* Handled — stop chain (for exclusive sources)
|
||||
Return 0 to let next server in chain try */
|
||||
}
|
||||
```
|
||||
|
||||
### Assembly Handler (Maximum Performance)
|
||||
|
||||
Handler signature:
|
||||
```asm
|
||||
myVBLHandler:
|
||||
; A1 = is_Data pointer (from struct Interrupt)
|
||||
; do fast work only
|
||||
MOVEQ #1, D0 ; handled — stop chain
|
||||
RTS
|
||||
; A1 = is_Data pointer
|
||||
; Must preserve D2-D7, A2-A6
|
||||
; May trash D0, D1, A0, A1
|
||||
MyVBLHandler:
|
||||
move.l (a1),a0 ; Load data pointer
|
||||
addq.l #1,FRAMECOUNT(a0)
|
||||
moveq #1,d0 ; Handled
|
||||
rts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Handler Rules
|
||||
|
||||
| Rule | Reason | Consequence |
|
||||
|---|---|---|
|
||||
| **No `Wait()` or `WaitPort()`** | Can't sleep at interrupt level | System freeze |
|
||||
| **No `AllocMem()` / `FreeMem()`** | May internally `Wait()` | System freeze |
|
||||
| **No DOS calls** | DOS is not reentrant | Corruption |
|
||||
| **No Intuition calls** | May `Wait()` internally | Deadlock |
|
||||
| **Preserve D2-D7, A2-A6** | Calling convention | Register corruption |
|
||||
| **Minimize execution time** | Blocks all lower-priority interrupts | Audio glitches, serial data loss |
|
||||
| **Use `Signal()` for deferred work** | Only safe IPC from interrupt context | — |
|
||||
| **Always acknowledge the interrupt** | Write to INTREQ to clear the request | Infinite interrupt loop |
|
||||
|
||||
---
|
||||
|
||||
## CIA Interrupts
|
||||
|
||||
CIA-A (at `$BFEC01`) generates level 2 interrupts. CIA-B (at `$BFD000`) generates level 6. Each CIA has an ICR (Interrupt Control Register) with 5 sources:
|
||||
CIA-A (`$BFE001`) generates level 2 (PORTS) interrupts. CIA-B (`$BFD000`) generates level 6 (EXTER) interrupts. Each CIA has an ICR (Interrupt Control Register) with 5 sources:
|
||||
|
||||
| Bit | Source |
|
||||
|---|---|
|
||||
| 0 | Timer A underflow |
|
||||
| 1 | Timer B underflow |
|
||||
| 2 | TOD alarm |
|
||||
| 3 | Serial register full |
|
||||
| 4 | Flag pin / FLG |
|
||||
| Bit | Source | CIA-A Use | CIA-B Use |
|
||||
|---|---|---|---|
|
||||
| 0 | Timer A underflow | Keyboard scan timer | System timer |
|
||||
| 1 | Timer B underflow | Available | Available |
|
||||
| 2 | TOD alarm | Real-time clock alarm | VSync counter |
|
||||
| 3 | Serial register (SP) | Keyboard data received | Available |
|
||||
| 4 | FLAG pin | Accent key / disk index | Available |
|
||||
|
||||
CIA interrupts are serviced via AddIntServer on `INTB_PORTS` (level 2, CIA-A) or `INTB_EXTER` (level 6, CIA-B).
|
||||
### CIA Interrupt Handler
|
||||
|
||||
```c
|
||||
/* CIA-A keyboard interrupt (level 2) */
|
||||
struct Interrupt kbdHandler;
|
||||
kbdHandler.is_Code = KbdISR;
|
||||
kbdHandler.is_Data = kbdData;
|
||||
kbdHandler.is_Node.ln_Pri = 120; /* High priority within level 2 */
|
||||
|
||||
AddIntServer(INTB_PORTS, &kbdHandler); /* Level 2 = CIA-A */
|
||||
|
||||
ULONG __interrupt KbdISR(struct Interrupt *irq __asm("a1"))
|
||||
{
|
||||
UBYTE icr = ciaa.ciaicr; /* Read + acknowledge CIA-A interrupts */
|
||||
|
||||
if (icr & 0x08) /* Bit 3 = serial port (keyboard data) */
|
||||
{
|
||||
UBYTE rawKey = ciaa.ciasdr;
|
||||
/* Process key... */
|
||||
Signal(mainTask, keySig);
|
||||
return 1; /* Handled */
|
||||
}
|
||||
|
||||
return 0; /* Not ours — pass to next handler */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Software Interrupts
|
||||
|
||||
Software interrupts run at level 1 priority but are scheduled by exec, not hardware. They're used for deferred interrupt processing — a hardware interrupt handler can queue a software interrupt to do longer processing at a lower priority:
|
||||
|
||||
```c
|
||||
/* Cause a software interrupt */
|
||||
struct Interrupt softInt;
|
||||
softInt.is_Code = MySoftHandler;
|
||||
softInt.is_Data = myData;
|
||||
softInt.is_Node.ln_Pri = 0; /* -32, -16, 0, +16, +32 are typical */
|
||||
|
||||
Cause(&softInt); /* LVO -78 */
|
||||
/* MySoftHandler runs at next opportunity (level 1) */
|
||||
```
|
||||
|
||||
### Software Interrupt Priorities
|
||||
|
||||
| Priority | Constant | Use |
|
||||
|---|---|---|
|
||||
| +32 | `SIH_PRIMOUSE` | Mouse/gameport processing |
|
||||
| +16 | — | High-priority deferred work |
|
||||
| 0 | — | Normal deferred work |
|
||||
| -16 | — | Low-priority deferred work |
|
||||
| -32 | `SIH_PRISERIAL` | Serial port processing |
|
||||
|
||||
---
|
||||
|
||||
## Disable / Enable vs Forbid / Permit
|
||||
|
||||
| Function | Effect | Scope |
|
||||
|---|---|---|
|
||||
| `Forbid()` | Disables task switching | Task-level (interrupts still run) |
|
||||
| `Permit()` | Re-enables task switching | Reverses `Forbid()` |
|
||||
| `Disable()` | Masks all hardware interrupts | Hardware + task switching |
|
||||
| `Enable()` | Unmasks hardware interrupts | Reverses `Disable()` |
|
||||
| Function | Effect | Scope | Max Safe Duration |
|
||||
|---|---|---|---|
|
||||
| `Forbid()` | Disables task switching | Tasks only (interrupts still run) | ~100 ms |
|
||||
| `Permit()` | Re-enables task switching | Reverses `Forbid()` | — |
|
||||
| `Disable()` | Masks all hardware interrupts | Hardware + task switching | **~250 µs** |
|
||||
| `Enable()` | Unmasks hardware interrupts | Reverses `Disable()` | — |
|
||||
|
||||
> [!CAUTION]
|
||||
> `Disable()` / `Enable()` can be held for only a few microseconds — never do I/O or complex operations inside a `Disable()` section.
|
||||
> **Caution**: `Disable()` / `Enable()` stop ALL hardware — serial data loss, audio DMA glitches, floppy read errors. Use only for accessing data structures shared between task and interrupt context.
|
||||
|
||||
---
|
||||
|
||||
## Pitfalls
|
||||
|
||||
### 1. Forgetting to Acknowledge
|
||||
|
||||
```c
|
||||
/* BUG — interrupt fires infinitely */
|
||||
ULONG MyHandler(void)
|
||||
{
|
||||
DoWork();
|
||||
return 1;
|
||||
/* Forgot: custom.intreq = INTF_VERTB; */
|
||||
/* INTREQ bit still set → interrupt fires again immediately → system hangs */
|
||||
}
|
||||
```
|
||||
|
||||
> **Note**: For server-chain interrupts (AddIntServer), exec handles INTREQ acknowledgment. For `SetIntVector`, you must do it yourself.
|
||||
|
||||
### 2. RemIntServer After Handler Memory Freed
|
||||
|
||||
```c
|
||||
/* BUG — handler struct on stack */
|
||||
void SetupVBL(void)
|
||||
{
|
||||
struct Interrupt vbl; /* ON STACK */
|
||||
AddIntServer(INTB_VERTB, &vbl);
|
||||
/* Function returns — stack frame destroyed */
|
||||
/* VBL interrupt fires → jumps to garbage → Guru */
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Spending Too Long in Handler
|
||||
|
||||
```c
|
||||
/* BUG — complex processing at interrupt level */
|
||||
ULONG MyAudioHandler(void)
|
||||
{
|
||||
DecodeMP3Frame(buffer); /* Takes >250 µs on 68000 */
|
||||
/* During this time, keyboard, serial, and disk are unserviced */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* CORRECT — signal task for heavy processing */
|
||||
ULONG MyAudioHandler(void)
|
||||
{
|
||||
Signal(decoderTask, decodeSig); /* ~5 µs */
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use server chains** (`AddIntServer`) for VBL, PORTS, EXTER — these are shared levels
|
||||
2. **Always `RemIntServer`** before exit or freeing handler memory
|
||||
3. **Keep handlers fast** — signal your main task for heavy work
|
||||
4. **Use software interrupts** for deferred processing from high-priority hardware handlers
|
||||
5. **Acknowledge interrupts** by writing to `INTREQ` when using `SetIntVector`
|
||||
6. **Preserve registers** D2-D7, A2-A6 in your handler
|
||||
7. **Use `Disable()`/`Enable()`** only to protect interrupt-shared data — never for general synchronization
|
||||
8. **Set appropriate priority** in `is_Node.ln_Pri` — higher priority handlers check first
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `hardware/intbits.h`, `hardware/cia.h`
|
||||
- ADCD 2.1: `AddIntServer`, `RemIntServer`, `SetIntVector`, `Disable`, `Forbid`
|
||||
- [cia_chips.md](../01_hardware/common/cia_chips.md) — CIA timer and ICR details
|
||||
- [custom_registers.md](../01_hardware/ocs_a500/custom_registers.md) — INTENA/INTREQ register listing
|
||||
- NDK39: `hardware/intbits.h`, `hardware/cia.h`, `exec/interrupts.h`
|
||||
- ADCD 2.1: `AddIntServer`, `RemIntServer`, `SetIntVector`, `Cause`, `Disable`, `Enable`
|
||||
- See also: [CIA Chips](../01_hardware/common/cia_chips.md) — CIA timer and ICR details
|
||||
- See also: [Custom Registers](../01_hardware/ocs_a500/custom_registers.md) — INTENA/INTREQ register listing
|
||||
- See also: [Multitasking](multitasking.md) — how interrupts drive the scheduler
|
||||
- *Amiga ROM Kernel Reference Manual: Exec* — interrupts chapter
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue