mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-12 16:16:28 +00:00
docs: expand final 3 Tier 3 articles + update all README indexes
Articles expanded: - gadgets.md: 403→804 lines — 5 antipatterns, GadTools→BOOPSI migration, form cookbook, historical timeline, modern analogies, 6 FAQ - screens.md: 582→992 lines — decision guide, 5 antipatterns, screen flipping/borderless/PAL-NTSC cookbooks, historical comparison, 7 FAQ - custom_loaders_and_drm.md: 152→500 lines — bootblock structure, 6 DRM systems, 5 antipatterns, trackloader cookbook, cracking scene history, modern analogies, 7 FAQ README indexes updated in 6 sections to reflect expanded content.
This commit is contained in:
parent
fa8ce16936
commit
27cad8128d
9 changed files with 785 additions and 27 deletions
|
|
@ -24,7 +24,7 @@ This section provides a systematic methodology for reverse engineering AmigaOS e
|
|||
| [static/code_vs_data_disambiguation.md](static/code_vs_data_disambiguation.md) | Distinguishing code bytes from data — IDA/Ghidra workflows |
|
||||
| [patching_techniques.md](patching_techniques.md) | Surgical binary patching methods |
|
||||
| [unpacking_and_decrunching.md](unpacking_and_decrunching.md) | Executable unpacking, decruncher architecture, and manual extraction |
|
||||
| [custom_loaders_and_drm.md](custom_loaders_and_drm.md) | Bypassing DOS, Trackloaders, and physical DRM tricks |
|
||||
| [custom_loaders_and_drm.md](custom_loaders_and_drm.md) | Custom bootblocks, trackloader architecture (raw MFM/Paula DMA), 6 DRM systems (Copylock, Psygnosis, EA, Gremlin), bootblock checksum, 5 antipatterns, trackloader identification cookbook, cracking scene history, modern analogies, 7 FAQ |
|
||||
| [anti_debugging.md](anti_debugging.md) | The Cracker vs. Developer arms race: Trace vector abuse, NMI defeat, CIA timers |
|
||||
| [games/whdload_architecture.md](games/whdload_architecture.md) | WHDLoad internals, slaves, resload_DiskLoad, and runtime memory patching |
|
||||
| [case_studies/](case_studies/) | Real-world RE walkthroughs |
|
||||
|
|
|
|||
|
|
@ -122,31 +122,379 @@ Rob Northen's genius was preventing crackers from stepping through the decryptio
|
|||
|
||||
---
|
||||
|
||||
## 4. Modern Analogies
|
||||
## 4. Bootblock Structure
|
||||
|
||||
| Amiga Paradigm | Modern Equivalent | Explanation |
|
||||
|---|---|---|
|
||||
| **Trackloader** | Custom Bootloader / Hypervisor | Bypassing the standard OS kernel to control hardware I/O directly for performance or DRM purposes. |
|
||||
| **Rob Northen Trace Abuse** | Denuvo Anti-Tamper / VMProtect | Using CPU exceptions, hardware-specific timing, and virtualization to break standard debuggers (x64 SEH/Vectored Exception Handling abuse). |
|
||||
| **MFM `$55555555` Decoding** | Base64 / AES Decryption loops | Transforming an obfuscated or wire-encoded stream back into executable binary code in memory before jumping to it. |
|
||||
The bootblock occupies the first two sectors (blocks 0 and 1, 1024 bytes total) of an Amiga floppy disk. Kickstart reads it via the ROM's built-in trackloader and decides what to do:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "Bootblock (1024 bytes)"
|
||||
SIG["Bytes 0–3\nSignature"]
|
||||
CHK["Bytes 4–7\nChecksum"]
|
||||
ROOT["Bytes 8–11\nRoot Block"]
|
||||
CODE["Bytes 12–1023\nBoot Code"]
|
||||
end
|
||||
|
||||
SIG -->|"'DOS\0'"| AMIGADOS[AmigaDOS Boot]
|
||||
SIG -->|"Other executable"| CUSTOM[Custom Bootblock]
|
||||
```
|
||||
|
||||
| Offset | Size | Field | Description |
|
||||
|--------|------|-------|-------------|
|
||||
| 0 | 4 bytes | `Signature` | `DOS\0` = standard AmigaDOS; any other value = custom bootblock |
|
||||
| 4 | 4 bytes | `Checksum` | Bootblock checksum (must validate for Kickstart to execute) |
|
||||
| 8 | 4 bytes | `RootBlock` | Block number of the root directory (AmigaDOS only) |
|
||||
| 12 | 1012 bytes | `BootCode` | 68000 executable code — the trackloader or game stub |
|
||||
|
||||
### Checksum Algorithm
|
||||
|
||||
Kickstart validates the bootblock checksum before executing. The algorithm is a simple 32-bit additive checksum with carry:
|
||||
|
||||
```c
|
||||
/* Bootblock checksum calculation */
|
||||
ULONG CalcBootChecksum(ULONG *block)
|
||||
{
|
||||
ULONG sum = 0;
|
||||
for (int i = 0; i < 256; i++) /* 1024 bytes / 4 = 256 longs */
|
||||
{
|
||||
ULONG val = block[i];
|
||||
if (val > ~sum)
|
||||
sum++; /* carry */
|
||||
sum += val;
|
||||
}
|
||||
return ~sum;
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> For custom bootblocks, the checksum must be correct or Kickstart ignores it. Crackers would modify the boot code and recalculate the checksum.
|
||||
|
||||
---
|
||||
|
||||
## 5. Reverse Engineering Best Practices
|
||||
## 5. DRM Systems Catalog
|
||||
|
||||
### 5.1 Rob Northen Copylock (1987–1993)
|
||||
|
||||
The most prevalent Amiga copy protection — used by **~70% of commercial games**. Over 1,500 titles shipped with Copylock.
|
||||
|
||||
| Aspect | Detail |
|
||||
|--------|--------|
|
||||
| **Creator** | Rob Northen Computing (UK) |
|
||||
| **Mechanism** | Timing-based key on track 0 + encrypted executable + trace exception abuse |
|
||||
| **Tracks affected** | Track 0 only (rarely track 79) |
|
||||
| **Defeated by** | Reading timing data, computing decryption key, patching checks |
|
||||
| **Preservation format** | IPF (CAPS) — ADF cannot represent the timing data |
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Game Executable] --> B[Encrypted Payload]
|
||||
A --> C[Copylock Wrapper]
|
||||
C -->|"Read Track 0"| D[Custom MFM Read]
|
||||
D -->|"Extract Timing Data"| E[Generate Decryption Key]
|
||||
E -->|"Decrypt & Jump"| B
|
||||
```
|
||||
|
||||
### 5.2 Psygnosis Protection
|
||||
|
||||
Used exclusively by Psygnosis (Lemmings, Shadow of the Beast, Agony):
|
||||
|
||||
- **Multiple protection tracks** spread across the disk (not just track 0)
|
||||
- **Non-standard sector sizes** — some tracks use 2 KB sectors instead of 512 bytes
|
||||
- **Custom sync words** per track — each track has a different `$xxxy` sync
|
||||
- Often combined with a **code wheel** or **manual lookup** for additional verification
|
||||
|
||||
### 5.3 EA (Electronic Arts) Protection
|
||||
|
||||
EA used several variants across their titles:
|
||||
|
||||
- **Long tracks** formatted to hold 12 sectors instead of 11 — standard copy tools can't reproduce
|
||||
- **Bad sectors** intentionally written — the game checks that specific sectors return read errors
|
||||
- **Modified header fields** — sector headers contain checksums that don't match their data
|
||||
|
||||
### 5.4 Gremlin Protection
|
||||
|
||||
Used by Gremlin Graphics (Zool, Fantasy World Dizzy):
|
||||
|
||||
- **Weak bits** on a specific track — the protection reads the same sector multiple times and checks that the bits flip
|
||||
- If the bits are stable (copied disk), the game exits with "Software failure"
|
||||
|
||||
### 5.5 Software Studios / Superior Software
|
||||
|
||||
Common on BBC Micro ports and UK budget titles:
|
||||
|
||||
- **Non-standard gap lengths** between sectors
|
||||
- **Sector numbering gaps** — sectors numbered 0,1,2,5,6,7 (missing 3,4)
|
||||
- The game reads sector 3 by index and checks it fails
|
||||
|
||||
### 5.6 Manual / Doc Check
|
||||
|
||||
Not a disk-based protection — a "soft" DRM approach:
|
||||
|
||||
| Type | Example | Implementation |
|
||||
|------|---------|---------------|
|
||||
| **Code wheel** | Secret of Monkey Island, Indiana Jones | Rotate physical wheel, enter visible word |
|
||||
| **Manual lookup** | Elite, Frontier | "Enter word 3 from paragraph 5 on page 42" |
|
||||
| **Symbol entry** | Dungeon Master | Enter sequence of symbols from the manual |
|
||||
|
||||
These were the most annoying for users and the easiest to crack — a simple byte patch removes the check.
|
||||
|
||||
---
|
||||
|
||||
## 6. Named Antipatterns
|
||||
|
||||
### "The Checksum Skip" — Patching Without Verification
|
||||
|
||||
```c
|
||||
/* BAD: When writing a custom bootblock for a cracker tool or
|
||||
WHDLoad slave, forgetting to recalculate the checksum.
|
||||
Kickstart refuses to execute the bootblock — silent failure. */
|
||||
UBYTE bootblock[1024] = { /* custom code */ };
|
||||
/* forgot to update checksum at offset 4-7 */
|
||||
WriteBootblock(disk, bootblock); /* won't boot! */
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Always calculate and store the checksum */
|
||||
ULONG *bb = (ULONG *)bootblock;
|
||||
bb[1] = 0; /* clear old checksum before calculating */
|
||||
bb[1] = CalcBootChecksum(bb);
|
||||
```
|
||||
|
||||
### "The Motor Assumption" — Assuming Drive is Spinning
|
||||
|
||||
```assembly
|
||||
; BAD: Many custom trackloaders assume the floppy motor is already
|
||||
; spinning when they start reading. On real hardware, the motor takes
|
||||
; ~500ms to reach full speed. If you jump straight to disk DMA,
|
||||
; the first reads are garbage.
|
||||
move.l #buffer, $dff020 ; DSKPTH - DMA pointer
|
||||
move.w #$8000|SECTOR_LEN, $dff024 ; DSKLEN - start reading NOW
|
||||
; Motor may not be up to speed — data corruption!
|
||||
```
|
||||
|
||||
```assembly
|
||||
; CORRECT: Wait for disk ready (or use a delay)
|
||||
bsr WaitForMotor ; spin up, wait ~500ms
|
||||
move.l #buffer, $dff020
|
||||
move.w #$8000|SECTOR_LEN, $dff024
|
||||
bsr WaitForDMAComplete
|
||||
```
|
||||
|
||||
### "The Single-Track Reliance" — All Protection on One Track
|
||||
|
||||
Copylock puts all protection on track 0. This is efficient (one check) but fragile:
|
||||
- A single bad sector on track 0 destroys the original disk permanently
|
||||
- Crackers know exactly where to look — they breakpoint on `$DFF07E` (DSKSYNC) reads
|
||||
- Once the timing key is extracted, all games using Copylock fall at once
|
||||
|
||||
Modern DRM learned this lesson: spread verification across multiple components (Denuvo checks CPU-specific timing + OS entropy + disk serial).
|
||||
|
||||
### "The Plaintext Key" — Storing Decryption Keys in RAM
|
||||
|
||||
```assembly
|
||||
; BAD: After Copylock decrypts the game, the decryption key remains
|
||||
; in a CPU register or memory location. If a cracker dumps RAM after
|
||||
; decryption, the key is exposed.
|
||||
bsr GenerateKey ; key in D0
|
||||
bsr DecryptPayload ; uses D0 as key
|
||||
; D0 still contains the key! A memory dump reveals it.
|
||||
```
|
||||
|
||||
Some Copylock variants zero the key register after use, but many don't — a common oversight that made cracking easier.
|
||||
|
||||
### "The Time-Bomb Check" — Fragile Timing Loops
|
||||
|
||||
```assembly
|
||||
; BAD: Protection that relies on exact CIA timer values.
|
||||
; This works on a stock A500 but fails on accelerated Amigas
|
||||
; (68030/040/060) because the timing loop completes too fast.
|
||||
move.l $bfe801, d0 ; Read CIA-A Timer A
|
||||
; ... execute some code ...
|
||||
move.l $bfe801, d1
|
||||
sub.l d0, d1 ; check elapsed time
|
||||
cmp.l #EXPECTED, d1 ; exact cycle count expected
|
||||
bne.s .protection_fail
|
||||
```
|
||||
|
||||
This is why many original games crash on accelerated Amigas — the timing check is CPU-speed-dependent. WHDLoad patches often fix this by NOP-ing the check.
|
||||
|
||||
---
|
||||
|
||||
## 7. Practical Cookbook: Identifying a Trackloader
|
||||
|
||||
Step-by-step guide to locating and understanding a game's trackloader in an emulator:
|
||||
|
||||
### Step 1: Set Up the Debugger
|
||||
|
||||
```
|
||||
; In WinUAE/FS-UAE debugger:
|
||||
; 1. Enable debugger (WinUAE: Misc → Enable Debugger)
|
||||
; 2. Boot the game from floppy image
|
||||
```
|
||||
|
||||
### Step 2: Break on Disk DMA
|
||||
|
||||
```
|
||||
; Set a write breakpoint on DSKLEN ($DFF024)
|
||||
; This fires every time the game starts a disk read
|
||||
w dff024 2
|
||||
|
||||
; When it breaks, examine:
|
||||
; - DSKPTH ($DFF020): where is data being read to?
|
||||
; - Stack trace: where is the read initiated from?
|
||||
```
|
||||
|
||||
### Step 3: Find the MFM Decoder
|
||||
|
||||
```
|
||||
; Search for the MFM decode constant $55555555
|
||||
; In the debugger:
|
||||
m 55555555
|
||||
|
||||
; Or in Ghidra/IDA, search for the constant:
|
||||
; The decode loop will be near disk register accesses
|
||||
```
|
||||
|
||||
### Step 4: Map the Load Sequence
|
||||
|
||||
```
|
||||
; Each time DSKLEN is written, note:
|
||||
; - Which track is being read (from CIA-B port B: $BFD100)
|
||||
; - How many words are being read (DSKLEN value)
|
||||
; - Where in RAM the data goes (DSKPTH)
|
||||
; - What happens after the read (decode? decrypt? direct jump?)
|
||||
```
|
||||
|
||||
### Step 5: Dump Decrypted Executable
|
||||
|
||||
```
|
||||
; Let the game fully boot and decrypt itself
|
||||
; Then take a full RAM dump:
|
||||
; WinUAE: Misc → Save Memory Dump
|
||||
; Or: save ramdump.bin 0 80000 (first 512KB)
|
||||
|
||||
; Now you have the decrypted game binary for static analysis
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Historical Context & Modern Analogies
|
||||
|
||||
### Evolution of Game DRM
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title Amiga Game DRM Timeline
|
||||
1985 : OS 1.0 — No copy protection\nGames use standard AmigaDOS files
|
||||
1986 : First custom bootblocks\nSimple track format changes
|
||||
1987 : Rob Northen Copylock v1\nTrack 0 timing + encryption\n 1988 : Psygnosis protection\nMulti-track, custom sync words
|
||||
1989 : EA long-track protection\n12-sector formatting
|
||||
1990 : Weak-bit protection\nGremlin, Gremlin Graphics
|
||||
1991 : Copylock v2 (enhanced)\nTrace exception abuse refined
|
||||
1992 : Manual/doc-check peak\nCode wheels, symbol entry
|
||||
1993 : Late-era Copylock\nLast commercial Amiga titles
|
||||
1995 : WHDLoad released\nHard drive patches for old games
|
||||
```
|
||||
|
||||
### The Cracking Scene
|
||||
|
||||
The Amiga cracking scene was one of the most active in computing history:
|
||||
|
||||
| Group | Notable For | Active Period |
|
||||
|-------|-------------|--------------|
|
||||
| **Fairlight** | Fast Copylock defeats, trained versions | 1987–1994 |
|
||||
| **Crystal** | Clean cracks, minimal patches | 1988–1995 |
|
||||
| **Paradroid** | Technical documentation of protections | 1989–1993 |
|
||||
| **Quarantine** | First to defeat Copylock v2 enhancements | 1990–1993 |
|
||||
| **Skid Row** | High-quality intros, fast releases | 1990–1996 |
|
||||
| **Delight** | Late-era Amiga protection removal | 1992–1997 |
|
||||
|
||||
> [!NOTE]
|
||||
> The cracking scene is documented here for historical and educational purposes — understanding these techniques is essential for software preservation and reverse engineering.
|
||||
|
||||
### Modern Analogies
|
||||
|
||||
| Amiga Concept | Modern Equivalent | Notes |
|
||||
|--------------|-------------------|-------|
|
||||
| Custom bootblock | UEFI custom boot manager / U-boot payload | Bypassing standard OS boot |
|
||||
| Trackloader (raw disk I/O) | Direct NVMe/SATA register access (DMA) | Bypassing OS filesystem for raw I/O |
|
||||
| MFM encoding | 8b/10b / 64b/66b line coding (PCIe/SATA) | Clock recovery encoding |
|
||||
| `$4489` sync word | K28.5 comma characters (8b/10b) | Framing / synchronization marker |
|
||||
| Rob Northen Copylock | Denuvo Anti-Tamper | CPU-specific timing + encrypted code |
|
||||
| Trace exception abuse | SEH chain abuse (anti-debug) / `RtlDecompressBuffer` hooking | Using CPU exceptions for code execution |
|
||||
| Weak bits (fuzzy bits) | TPM-bound encryption keys | Tying execution to unique hardware |
|
||||
| Manual/doc check | Online activation / always-online DRM | "Something you have" verification |
|
||||
| WHDLoad slave | DOSBox config / ScummVM engine patch | Compatibility layer for old software |
|
||||
| IPF preservation format | MAME CHD (Compressed Hunks of Data) | Preservation-grade disk images with timing |
|
||||
|
||||
---
|
||||
|
||||
## 9. Reverse Engineering Best Practices
|
||||
|
||||
1. **Memory Dumps over Static Analysis**: Because most commercial games are packed (Imploder, PowerPacker) and encrypted (Copylock), static analysis of the binary on disk is often useless. Use WinUAE/FS-UAE's built-in debugger to let the game boot, decrypt itself into RAM, and then take a memory dump to analyze in IDA Pro.
|
||||
2. **Identify `$DFF024` (DSKLEN)**: Set write breakpoints on `$DFF024` in your emulator. This is the hardware trigger to start a disk DMA read. When it hits, look at the stack to find the trackloader code.
|
||||
3. **Beware of `$4.w` (ExecBase)**: If a game reads `$4.w` and immediately calls `Forbid()` (offset `-132`), it is preparing to kill the OS. Put your breakpoints *before* this happens if you are relying on an OS-level debugger.
|
||||
4. **Use IPF, not ADF, for originals**: Standard ADF format cannot represent non-standard track formats, weak bits, or timing data. Use the SPS/IPF format for preservation-grade images.
|
||||
5. **Action Replay for live debugging**: Hardware cartridges like Action Replay III can freeze the machine at any point — even after the OS is disabled. invaluable for examining custom trackloader state.
|
||||
6. **Compare cracked vs. original**: Loading both an original IPF and a cracked ADF into Ghidra and diffing the code makes the protection check obvious.
|
||||
7. **Check for WhdLoad slaves first**: Before reverse-engineering a game's loader, check if a WHDLoad slave already exists — it may document the load addresses and file format.
|
||||
|
||||
---
|
||||
|
||||
## 6. FAQ
|
||||
## 10. FAQ
|
||||
|
||||
**Q: Why did games use Trackloaders instead of standard AmigaDOS files?**
|
||||
A: AmigaDOS (OFS) has significant overhead. It requires memory for file buffers, wastes bytes on directory structures, and the floppy motor turns off between file reads. A custom trackloader keeps the motor spinning and reads entire raw cylinders into RAM sequentially, reducing loading times from minutes to seconds.
|
||||
|
||||
**Q: How do WHDLoad patches work with Trackloaders?**
|
||||
A: WHDLoad is an OS-replacement system that patches games to run from hard drives. A WHDLoad "Slave" (the patch file) replaces the game's custom trackloader (which expects floppy hardware) with calls to WHDLoad's `resload_DiskLoad` API, emulating the floppy load via standard hard drive I/O.
|
||||
A: WHDLoad is an OS-replacement system that patches games to run from hard drives. A WHDLoad "Slave" (the patch file) replaces the game's custom trackloader (which expects floppy hardware) with calls to WHDLoad's `resload_DiskLoad` API, emulating the floppy load via standard hard drive I/O.
|
||||
|
||||
**Q: If Copylock relies on a physical disk flaw, how do cracked ADFs work?**
|
||||
A: Cracked disk images (ADFs) contain the already-decrypted game executable, with the Copylock routine completely bypassed or stubbed out (`NOP` instructions). The physical flaw cannot be represented in a standard ADF, which is why original, uncracked games must be preserved in IPF (Interchangeable Preservation Format) instead of ADF.
|
||||
|
||||
**Q: Can I write a custom bootblock to a standard Amiga floppy?**
|
||||
A: Yes — any Amiga floppy drive can write the first two sectors (the bootblock) using standard `trackdisk.device` commands (`TD_WRITE` to block 0). However, writing non-standard track formats (long tracks, custom sync words) requires direct hardware access to Paula's disk DMA.
|
||||
|
||||
**Q: How does the CAPS/SPS preservation project work?**
|
||||
A: The Classic Amiga Preservation Society (CAPS, now SPS — Software Preservation Society) uses modified floppy drives (or KryoFlux devices) to read the raw magnetic flux transitions, not just the decoded data. This captures timing information, weak bits, and non-standard formats that ADF cannot represent. The result is stored in IPF format.
|
||||
|
||||
**Q: Why do some games work on some Amiga models but not others?**
|
||||
A: Trackloaders that use timing loops calibrated for the 68000 (7.09 MHz) fail on faster CPUs (68020+ at 14/25 MHz). The timing loop completes too quickly, and the protection check fails. This is separate from the game logic — the game itself may run fine, but the copy protection rejects the disk.
|
||||
|
||||
**Q: What's the difference between ADF, IPF, and DMS formats?**
|
||||
A:
|
||||
- **ADF** (Amiga Disk File): Standard 880 KB image of 80 tracks × 11 sectors × 512 bytes. Cannot represent copy protection.
|
||||
- **IPF** (Interchangeable Preservation Format): Preservation-grade format that stores raw MFM data with timing, weak bits, and non-standard geometry.
|
||||
- **DMS** (Disk Masher System): Compressed ADF — essentially a ZIP for Amiga disks. Popular for BBS distribution but cannot represent protection either.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
### NDK Headers & Hardware
|
||||
|
||||
- `hardware/cia.h` — CIA timer registers (`$BFE801`, `$BFD100`)
|
||||
- `hardware/custom.h` — Disk DMA registers (`DSKSYNC`, `DSKPTH`, `DSKLEN`)
|
||||
- `resources/disk.h` — `disk.resource` for trackdisk.device arbitration
|
||||
|
||||
### Preservation & Documentation
|
||||
|
||||
- **SPS (Software Preservation Society)**: https://www.softpres.org — IPF preservation format specification
|
||||
- **KryoFlux**: http://www.kryoflux.com — USB floppy controller for flux-level reading
|
||||
- **CAPS/SPS IPF Library**: https://www.softpres.org/games — preserved original disk images
|
||||
|
||||
### Cracking & Reverse Engineering
|
||||
|
||||
- AmigaOS ROM Kernel Manual: hardware register map, boot sequence
|
||||
- **WHDLoad**: https://www.whdload.de — hard drive installers for Amiga games
|
||||
- **WinUAE Debugger**: built-in MC68000 debugger with hardware register breakpoints
|
||||
|
||||
### Related Knowledge Base Articles
|
||||
|
||||
- [Anti-Debugging & Arms Race](anti_debugging.md) — Copylock trace abuse, anti-cracker techniques
|
||||
- [Unpacking & Decrunching](unpacking_and_decrunching.md) — PowerPacker, Imploder, TDI crunchers
|
||||
- [Trackdisk Device](../10_devices/trackdisk.md) — standard floppy device, MFM encoding, track layout
|
||||
- [Methodology](methodology.md) — general reverse engineering workflow
|
||||
- [Static Analysis](static/) — IDA Pro, Ghidra setup and usage
|
||||
- [Dynamic Analysis](dynamic/) — WinUAE debugger, HRTmon, Action Replay
|
||||
- [Patching Techniques](patching_techniques.md) — binary patching, WHDLoad slave development
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ The Amiga graphics system is built on custom DMA-driven hardware (Agnus/Alice +
|
|||
| [sprites.md](sprites.md) | Hardware sprites: DMA engine, data format, attached 15-color sprites, multiplexing, AGA enhancements, priority control |
|
||||
| [rastport.md](rastport.md) | RastPort drawing context: draw modes, patterns, layer clipping, text pipeline, blitter minterms |
|
||||
| [views.md](views.md) | View + ViewPort pipeline: 3-stage Mermaid diagram, ViewPort chaining (split screens), ColorMap/LoadRGB4, named antipatterns, Copper vs Views decision flowchart, modern GPU analogies |
|
||||
| [text_fonts.md](text_fonts.md) | TextFont bitmap layout, baseline rendering, algorithmic styles, AvailFonts enumeration |
|
||||
| [text_fonts.md](text_fonts.md) | TextFont bitmap layout, baseline rendering, algorithmic styles, AvailFonts, ColorTextFont, Compugraphic outlines, font scaling, 3 cookbooks, 4 antipatterns, 6 FAQ |
|
||||
| [pixel_conversion.md](pixel_conversion.md) | Chunky ↔ Planar conversion deep dive: naive, merge/butterfly (Kalms), Copper Chunky, Akiko hardware, Blitter-assisted, RTG bypass, SoA/AoS theory, GPU swizzle modern parallels |
|
||||
| [animation.md](animation.md) | GEL system deep dive: BOBs, VSprites, AnimObs, hardware foundation (Blitter/Copper/Sprite interaction), collision detection, double buffering, performance tuning |
|
||||
| [rtg_programming.md](rtg_programming.md) | Retargetable Graphics (CyberGraphX/Picasso96): Planar vs Chunky, LockBitMapTags, Pixel Formats, Direct VRAM rendering |
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ Intuition is the AmigaOS windowing system and user interface manager. It sits be
|
|||
| File | Description |
|
||||
|---|---|
|
||||
| [intuition_base.md](intuition_base.md) | IntuitionBase — library versioning, global state fields, ViewLord, LockIBase, function overview |
|
||||
| [screens.md](screens.md) | Screens — Copper mechanics, display modes (OCS/ECS/AGA/RTG), dragging, resolution tables |
|
||||
| [windows.md](windows.md) | Windows — WA_ tags, refresh modes, window types, coordinate system, lifecycle |
|
||||
| [gadgets.md](gadgets.md) | Gadgets — GadTools creation, raw struct Gadget, prop/string gadgets, runtime updates |
|
||||
| [menus.md](menus.md) | Menus — GadTools NewMenu, event handling, multi-select, checkmarks, keyboard shortcuts |
|
||||
| [screens.md](screens.md) | Screens — Copper mechanics, display modes (OCS/ECS/AGA/RTG), dragging, resolution tables, screen type decision guide, 5 antipatterns, screen flipping/borderless/PAL-NTSC cookbooks, modern analogies, 7 FAQ |
|
||||
| [windows.md](windows.md) | Windows — WA_ tags, refresh modes, window types, coordinate system, lifecycle, 5 antipatterns, decision guide, 3 cookbooks, modern analogies, 7 FAQ |
|
||||
| [gadgets.md](gadgets.md) | Gadgets — GadTools creation, raw struct Gadget, prop/string gadgets, runtime updates, 5 antipatterns, GadTools→BOOPSI migration guide, form cookbook, historical timeline, 6 FAQ |
|
||||
| [menus.md](menus.md) | Menus — GadTools NewMenu, event handling, multi-select, checkmarks, keyboard shortcuts, render chain diagram, 5 antipatterns, lifecycle cookbook, 6 FAQ |
|
||||
| [requesters.md](requesters.md) | Requesters — EasyRequest, ASL file/font/screenmode dialogs, non-blocking pattern |
|
||||
| [idcmp.md](idcmp.md) | IDCMP — event architecture, class reference, shared ports, antipatterns, use-case cookbook |
|
||||
| [boopsi.md](boopsi.md) | BOOPSI — OOP dispatcher model, ICA interconnection, custom class tutorial, class hierarchy |
|
||||
|
|
|
|||
|
|
@ -558,6 +558,395 @@ if (modeID != INVALID_ID)
|
|||
|
||||
---
|
||||
|
||||
## Screen Type Decision Guide
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
START["Need a screen?"] --> Q1{"Need specific\nresolution/depth?"}
|
||||
Q1 -->|No| Q2{"Other apps should\nshare this screen?"}
|
||||
Q1 -->|Yes| CUSTOM["CUSTOMSCREEN\nOwn resolution, palette, lifetime"]
|
||||
Q2 -->|Yes| PUBLIC["PUBLICSCREEN\nNamed, discoverable by other apps"]
|
||||
Q2 -->|No| WB["WBENCHSCREEN\nUse Workbench, no extra memory"]
|
||||
|
||||
CUSTOM --> Q3{"Need true-color\nor > 256 colors?"}
|
||||
Q3 -->|Yes| RTG["RTG mode\nCyberGraphX / Picasso96"]
|
||||
Q3 -->|No| NATIVE["Native chipset mode\nBestModeID() to pick"]
|
||||
|
||||
style WB fill:#e8f5e9,stroke:#4caf50,color:#333
|
||||
style PUBLIC fill:#e8f4fd,stroke:#2196f3,color:#333
|
||||
style CUSTOM fill:#fff3e0,stroke:#ff9800,color:#333
|
||||
style RTG fill:#fce4ec,stroke:#e91e63,color:#333
|
||||
```
|
||||
|
||||
| Choice | Memory Cost | Flexibility | When to Use |
|
||||
|--------|------------|-------------|-------------|
|
||||
| **Workbench** | None (shared) | Constrained to user's WB mode | Tools, utilities, simple apps |
|
||||
| **Public Screen** | ~200–600 KB | Moderate — fixed at creation | Multi-app suites (MUI, email + browser) |
|
||||
| **Custom Screen** | ~200–600 KB | Full — you own everything | Games, paint programs, video tools |
|
||||
| **RTG Custom** | 1–4 MB | Full + true color | High-end graphics on gfx-card systems |
|
||||
|
||||
---
|
||||
|
||||
## Named Antipatterns
|
||||
|
||||
### "The Orphan Screen" — Leaking a Custom Screen
|
||||
|
||||
```c
|
||||
/* BAD: Opening a custom screen but losing the pointer.
|
||||
The screen stays open, consuming hundreds of KB of chip RAM,
|
||||
and there's no way to close it without resetting. */
|
||||
void ShowSplash(void)
|
||||
{
|
||||
OpenScreenTags(NULL,
|
||||
SA_Type, CUSTOMSCREEN,
|
||||
SA_Depth, 5,
|
||||
SA_Title, "Splash",
|
||||
TAG_DONE);
|
||||
/* No pointer saved — screen is now a memory leak! */
|
||||
}
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Always store and eventually close */
|
||||
struct Screen *splashScr = NULL;
|
||||
|
||||
void ShowSplash(void)
|
||||
{
|
||||
splashScr = OpenScreenTags(NULL,
|
||||
SA_Type, CUSTOMSCREEN,
|
||||
SA_Depth, 5,
|
||||
SA_Title, "Splash",
|
||||
TAG_DONE);
|
||||
}
|
||||
|
||||
void HideSplash(void)
|
||||
{
|
||||
if (splashScr)
|
||||
{
|
||||
CloseScreen(splashScr);
|
||||
splashScr = NULL;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### "The Hardcoded Mode" — Assuming Display IDs
|
||||
|
||||
```c
|
||||
/* BAD: Hardcoded PAL HiRes display ID.
|
||||
On an NTSC Amiga, or one without ECS, this mode may not exist.
|
||||
OpenScreenTags returns NULL — silent failure. */
|
||||
struct Screen *scr = OpenScreenTags(NULL,
|
||||
SA_DisplayID, 0x00029000, /* PAL HiRes — may not exist */
|
||||
SA_Width, 640,
|
||||
SA_Height, 256,
|
||||
SA_Depth, 4,
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Query the display database */
|
||||
ULONG modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, 640,
|
||||
BIDTAG_NominalHeight, 256,
|
||||
BIDTAG_Depth, 4,
|
||||
TAG_DONE);
|
||||
|
||||
if (modeID == INVALID_ID)
|
||||
{
|
||||
/* No suitable mode — fall back to Workbench */
|
||||
modeID = INVALID_ID; /* OpenScreen on WB */
|
||||
}
|
||||
|
||||
struct Screen *scr = OpenScreenTags(NULL,
|
||||
SA_DisplayID, modeID,
|
||||
SA_Width, 640,
|
||||
SA_Height, 256,
|
||||
SA_Depth, 4,
|
||||
SA_Type, CUSTOMSCREEN,
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
### "The Stale Pointer" — Using Screen After Close
|
||||
|
||||
```c
|
||||
/* BAD: Caching a public screen pointer across operations.
|
||||
If the screen owner closes it between your Lock and use,
|
||||
you dereference freed memory — crash. */
|
||||
struct Screen *scr = LockPubScreen("MYAPP");
|
||||
UnlockPubScreen(NULL, scr);
|
||||
/* ... 100ms passes, owner closes "MYAPP" screen ... */
|
||||
DrawSomething(scr->RastPort); /* USE AFTER FREE */
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Re-lock immediately before each use */
|
||||
struct Screen *scr = LockPubScreen("MYAPP");
|
||||
if (scr)
|
||||
{
|
||||
DrawSomething(&scr->RastPort);
|
||||
UnlockPubScreen(NULL, scr);
|
||||
}
|
||||
```
|
||||
|
||||
### "The Forced Close" — CloseScreen with Windows Open
|
||||
|
||||
```c
|
||||
/* BAD: Closing a screen while visitor windows still exist.
|
||||
CloseScreen() returns FALSE — the screen stays open.
|
||||
But you've already freed your own window — confusion. */
|
||||
CloseWindow(myWin);
|
||||
CloseScreen(myScreen); /* May return FALSE — visitors still here */
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: For public screens, go private first */
|
||||
PubScreenStatus(myScreen, PSNF_PRIVATE); /* block new visitors */
|
||||
|
||||
/* Wait for remaining visitor windows to close */
|
||||
while (myScreen->FirstWindow)
|
||||
Delay(10);
|
||||
|
||||
CloseScreen(myScreen); /* now guaranteed to succeed */
|
||||
```
|
||||
|
||||
### "The Layer Lock Trap" — Calling Intuition Inside LockLayerInfo
|
||||
|
||||
```c
|
||||
/* BAD: Locking LayerInfo then calling any Intuition function.
|
||||
Intuition needs LayerInfo internally — instant deadlock. */
|
||||
LockLayerInfo(&scr->LayerInfo);
|
||||
RefreshWindowFrame(win); /* DEADLOCK */
|
||||
UnlockLayerInfo(&scr->LayerInfo);
|
||||
```
|
||||
|
||||
```c
|
||||
/* CORRECT: Never hold LayerInfo across Intuition calls.
|
||||
If you need layer info, copy what you need, unlock, then proceed. */
|
||||
LONG clipX = scr->Width; /* just read directly — it's atomic */
|
||||
LONG clipY = scr->Height;
|
||||
/* No lock needed for simple reads */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Practical Cookbooks
|
||||
|
||||
### Cookbook 1: Screen Flipping (Game Double-Buffer)
|
||||
|
||||
Games often flip between two screens — the visible one and the hidden one being rendered:
|
||||
|
||||
```c
|
||||
#include <proto/graphics.h>
|
||||
#include <proto/intuition.h>
|
||||
|
||||
struct Screen *gameScreens[2];
|
||||
int currentScreen = 0;
|
||||
|
||||
void InitGameScreens(void)
|
||||
{
|
||||
ULONG modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, 320,
|
||||
BIDTAG_NominalHeight, 256,
|
||||
BIDTAG_Depth, 5, /* 32 colors */
|
||||
TAG_DONE);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
gameScreens[i] = OpenScreenTags(NULL,
|
||||
SA_Width, 320,
|
||||
SA_Height, 256,
|
||||
SA_Depth, 5,
|
||||
SA_DisplayID, modeID,
|
||||
SA_Type, CUSTOMSCREEN,
|
||||
SA_Quiet, TRUE, /* no title bar — full screen */
|
||||
SA_Behind, (i == 1), /* second screen opens behind */
|
||||
TAG_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
void FlipScreen(void)
|
||||
{
|
||||
currentScreen = 1 - currentScreen;
|
||||
ScreenToFront(gameScreens[currentScreen]);
|
||||
}
|
||||
|
||||
struct Screen *GetRenderScreen(void)
|
||||
{
|
||||
return gameScreens[1 - currentScreen]; /* the hidden one */
|
||||
}
|
||||
|
||||
void CleanupGameScreens(void)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
CloseScreen(gameScreens[i]);
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> `ScreenToFront()` / `ScreenToBack()` work on the screen depth arrangement, not the Copper list. Both screens are always being displayed — only the stacking order changes.
|
||||
|
||||
### Cookbook 2: Borderless Fullscreen Application
|
||||
|
||||
```c
|
||||
/* Full-screen utility or game — no drag bar, no system gadgets,
|
||||
every pixel belongs to the application. */
|
||||
struct Screen *scr = OpenScreenTags(NULL,
|
||||
SA_Width, 320,
|
||||
SA_Height, 256,
|
||||
SA_Depth, 5,
|
||||
SA_Type, CUSTOMSCREEN,
|
||||
SA_Quiet, TRUE, /* no title bar */
|
||||
SA_ShowTitle, FALSE, /* redundant with SA_Quiet, but explicit */
|
||||
SA_Pens, (ULONG)~0,
|
||||
TAG_DONE);
|
||||
|
||||
/* Full-screen window (no borders, fills entire screen) */
|
||||
struct Window *win = OpenWindowTags(NULL,
|
||||
WA_CustomScreen, scr,
|
||||
WA_Left, 0,
|
||||
WA_Top, 0,
|
||||
WA_Width, scr->Width,
|
||||
WA_Height, scr->Height,
|
||||
WA_Borderless, TRUE,
|
||||
WA_Activate, TRUE,
|
||||
WA_RMBTrap, TRUE, /* we handle right-click ourselves */
|
||||
WA_IDCMP, IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS |
|
||||
IDCMP_MOUSEMOVE,
|
||||
WA_Backdrop, TRUE, /* behind title bar area (irrelevant here) */
|
||||
TAG_DONE);
|
||||
|
||||
/* Use scr->RastPort or win->RPort for full-screen drawing */
|
||||
```
|
||||
|
||||
### Cookbook 3: PAL/NTSC Safe Screen Opening
|
||||
|
||||
```c
|
||||
/* Open a screen that works on both PAL and NTSC machines.
|
||||
Strategy: query the display database for the best available mode. */
|
||||
|
||||
#include <proto/graphics.h>
|
||||
#include <graphics/displayinfo.h>
|
||||
|
||||
struct Screen *OpenSafeScreen(ULONG width, ULONG height, ULONG depth)
|
||||
{
|
||||
/* Step 1: Find the best matching mode */
|
||||
ULONG modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, width,
|
||||
BIDTAG_NominalHeight, height,
|
||||
BIDTAG_Depth, depth,
|
||||
TAG_DONE);
|
||||
|
||||
if (modeID == INVALID_ID)
|
||||
{
|
||||
/* Fallback: try the Workbench screen's mode */
|
||||
struct Screen *wb = LockPubScreen(NULL);
|
||||
if (wb)
|
||||
{
|
||||
modeID = GetVPModeID(&wb->ViewPort);
|
||||
UnlockPubScreen(NULL, wb);
|
||||
}
|
||||
}
|
||||
|
||||
if (modeID == INVALID_ID)
|
||||
return NULL; /* no usable display mode at all */
|
||||
|
||||
/* Step 2: Query actual dimensions for this mode */
|
||||
struct DimensionInfo di;
|
||||
if (GetDisplayInfoData(NULL, (UBYTE *)&di, sizeof(di),
|
||||
DTAG_DIMS, modeID))
|
||||
{
|
||||
/* Use the mode's actual dimensions, not our requested ones */
|
||||
return OpenScreenTags(NULL,
|
||||
SA_DisplayID, modeID,
|
||||
SA_Width, di.Nominal.MaxX - di.Nominal.MinX + 1,
|
||||
SA_Height, di.Nominal.MaxY - di.Nominal.MinY + 1,
|
||||
SA_Depth, depth,
|
||||
SA_Type, CUSTOMSCREEN,
|
||||
SA_Pens, (ULONG)~0,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Historical Context & Modern Analogies
|
||||
|
||||
### Competitive Landscape
|
||||
|
||||
| Platform | Multiple Resolutions | Screen Dragging | Independent Palettes | Notes |
|
||||
|----------|---------------------|-----------------|---------------------|-------|
|
||||
| **AmigaOS** | Yes — each screen independent | Yes — real-time drag | Yes — per-screen palette | Unique — no other platform does this |
|
||||
| **Mac OS (Classic)** | No — one resolution globally | N/A | No — one global palette | Switchable via Monitors control panel (reboot) |
|
||||
| **Windows 3.x** | No — one resolution globally | N/A | No — 16-color global palette | ALT+TAB switches between apps, not screens |
|
||||
| **Atari ST** | No — fixed 640×400 (mono) or 320×200 (color) | N/A | No — fixed ST palette | Resolution requires hardware dip switches |
|
||||
| **X11** | Yes — per-screen (Xinerama/XRandR) | No — virtual desktop instead | Yes — per-colormap | "Screen" means X screen, not Amiga screen |
|
||||
|
||||
The Amiga's multi-resolution coexistence was possible because the Copper could change display parameters mid-frame at zero CPU cost. Every other platform required the entire display to use one mode.
|
||||
|
||||
**Screen dragging** was Amiga-exclusive. The Mac had "window shuffling" (front/back), Windows had ALT+TAB, and X11 had virtual desktops — but none allowed dragging one resolution's display area to reveal a completely different resolution underneath, in real time.
|
||||
|
||||
### Modern Analogies
|
||||
|
||||
| Amiga Concept | Modern Equivalent | Notes |
|
||||
|--------------|-------------------|-------|
|
||||
| `OpenScreenTags()` | macOS `NSScreen` + `NSWindow` / X11 `XCreateWindow` | Amiga screens are independent display contexts |
|
||||
| `CUSTOMSCREEN` | Fullscreen exclusive mode (DirectX / Vulkan) | Application owns the entire display |
|
||||
| `PUBLICSCREEN` | Shared desktop / virtual desktop | Multiple apps share one display surface |
|
||||
| `WBENCHSCREEN` | Primary display / main monitor | Default shared screen |
|
||||
| Screen dragging | Virtual desktop panning / Spaces (macOS) | Amiga: physical drag; Modern: key-combo switch |
|
||||
| `ScreenToFront()` / `ScreenToBack()` | `SetForegroundWindow()` / `NSWindow.orderFront` | Depth arrangement |
|
||||
| Copper mid-frame mode switch | Not possible on modern GPUs | GPUs scan from a single framebuffer |
|
||||
| `BestModeID()` | `EnumDisplaySettings()` / `CGDisplayAvailableModes()` | Query available modes |
|
||||
| `LockPubScreen()` | `CGWindowListCopyWindowInfo()` / X11 `_NET_CLIENT_LIST` | Discover shared screens |
|
||||
| `ViewPort` + `ColorMap` | `CRTC` + `LUT` on VGA / modern monitor | Hardware display timing |
|
||||
| `SA_Overscan` | Overscan / underscan in GPU control panel | Edge-of-screen area usage |
|
||||
| Interlaced flicker | N/A — modern displays are progressive | Amiga-specific CRT artifact |
|
||||
|
||||
---
|
||||
|
||||
## Use Cases
|
||||
|
||||
| Application | Screen Type | Resolution | Notable Pattern |
|
||||
|-------------|------------|------------|-----------------|
|
||||
| **Workbench** | WBENCHSCREEN | User-configured (default HiRes) | Persistent system screen |
|
||||
| **Games (most)** | CUSTOMSCREEN, SA_Quiet | LoRes 320×256, 4–5 bitplanes | Borderless fullscreen, no drag bar |
|
||||
| **Deluxe Paint** | CUSTOMSCREEN | LoRes or HAM depending on mode | Own palette, own resolution, screen dragging to access WB |
|
||||
| **Word processors** | WBENCHSCREEN or PUBLICSCREEN | HiRes interlaced 640×512 | Share Workbench to save chip RAM |
|
||||
| **Video tools (OPALVision, Video Toaster)** | CUSTOMSCREEN + genlock | Specific to video standard (NTSC/PAL) | Genlock overlay compositing |
|
||||
| **DTP (PageStream)** | CUSTOMSCREEN, SA_AutoScroll | HiRes interlaced with virtual scroll | Screen larger than display, autoscroll |
|
||||
| **MUI applications** | PUBLICSCREEN | User-configured | Named public screen shared by MUI apps |
|
||||
| **Terminal emulators** | WBENCHSCREEN | HiRes 640×256+ | Open on Workbench to multitask |
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Can I have two screens at different color depths on screen at the same time?**
|
||||
A: Yes — this is one of the Amiga's signature features. Each screen has its own ViewPort with its own ColorMap. The Copper switches palette registers mid-frame. You can have a 4-color Workbench screen above a 32-color game screen, both fully visible.
|
||||
|
||||
**Q: How much chip RAM does a screen consume?**
|
||||
A: It depends on resolution and depth. A 640×256 4-bitplane screen uses 640 × 256 × 4 / 8 = 81,920 bytes for bitplanes, plus ~5–10 KB for structures, color tables, and the Copper list. A 320×256 5-bitplane screen uses ~51,200 bytes. Interlaced screens double the height, doubling the cost.
|
||||
|
||||
**Q: Can I prevent the user from dragging my custom screen?**
|
||||
A: Not easily. Screen dragging is handled by Intuition at a level above applications. Setting `SA_Quiet` removes the title bar (making it harder to grab), but Left-Amiga + mouse drag still works. Games typically just handle `IDCMP_CHANGEWINDOW` / `IDCMP_SCREENPOSITION` to detect and respond to unexpected moves.
|
||||
|
||||
**Q: What happens to my window when the user drags my screen behind another?**
|
||||
A: Your window continues to exist and receive events normally. However, it's no longer visible. Keyboard events still route to the active window on your screen. Mouse events route to whichever screen the pointer is over.
|
||||
|
||||
**Q: Can I open a window on a screen owned by another process?**
|
||||
A: Yes — if the screen is a public screen (opened with `SA_PubName`). Use `LockPubScreen("name")` to get the screen pointer, open your window with `WA_PubScreen`, then `UnlockPubScreen()`. You cannot open windows on another process's `CUSTOMSCREEN`.
|
||||
|
||||
**Q: How do I enumerate all open screens?**
|
||||
A: Walk the `IntuitionBase->FirstScreen` linked list. Each screen's `NextScreen` field points to the next. You must lock Intuition with `LockIBase()` / `UnlockIBase()` to prevent the list from changing while you traverse it.
|
||||
|
||||
**Q: Why does `BestModeID()` return `INVALID_ID` on my A500?**
|
||||
A: `BestModeID()` requires ECS or later to support queries beyond the basic modes. On OCS machines, use the known OCS mode constants (`LORES_KEY`, `HIRES_KEY`, etc.) directly, or fall back to `WBENCHSCREEN` if the query fails.
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Prefer public screens** over custom screens — saves memory and lets users consolidate
|
||||
|
|
@ -570,13 +959,34 @@ if (modeID != INVALID_ID)
|
|||
8. **Never hold layer locks** while calling Intuition functions
|
||||
9. **Use Right-Amiga** for application shortcuts — Left-Amiga is reserved for system use
|
||||
10. **Test with multiple screens** at different resolutions to verify your input handling works correctly
|
||||
11. **Use `SA_Quiet` for games** — removes title bar for immersive fullscreen
|
||||
12. **Always check `OpenScreenTags()` return** — `NULL` means the mode is unavailable or memory is exhausted
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK 3.9: `intuition/screens.h`, `intuition/intuition.h`
|
||||
- ADCD 2.1: `OpenScreenTagList()`, `CloseScreen()`, `LockPubScreen()`, `PubScreenStatus()`
|
||||
- AmigaOS Reference Manual (RKRM): Libraries, Chapter 3 — Intuition Screens
|
||||
- AmigaOS Reference Manual (RKRM): Libraries, Chapter 5 — Intuition Input and IDCMP
|
||||
- Hardware Reference Manual: Custom Chip Register Map, Copper List Programming
|
||||
### NDK Headers
|
||||
|
||||
- `intuition/screens.h` — `struct Screen`, `SA_*` tag definitions, `CUSTOMSCREEN`/`PUBLICSCREEN`/`WBENCHSCREEN`
|
||||
- `intuition/intuition.h` — `struct Window`, `WA_*` tags, IDCMP flags
|
||||
- `graphics/displayinfo.h` — Display IDs, `DimensionInfo`, `BestModeID()`
|
||||
- `graphics/gfxbase.h` — `GfxBase->DisplayFirst` for display database traversal
|
||||
|
||||
### Autodocs
|
||||
|
||||
- ADCD 2.1: `OpenScreenTagList()`, `CloseScreen()`, `ScreenToFront()`, `ScreenToBack()`
|
||||
- ADCD 2.1: `LockPubScreen()`, `UnlockPubScreen()`, `PubScreenStatus()`, `LockIBase()`
|
||||
- ADCD 2.1: `BestModeID()`, `NextDisplayInfo()`, `GetDisplayInfoData()`
|
||||
- ADCD 2.1: `GetScreenDrawInfo()`, `FreeScreenDrawInfo()`, `GetVPModeID()`
|
||||
|
||||
### Related Knowledge Base Articles
|
||||
|
||||
- [Copper](../08_graphics/copper.md) — the hardware mechanism that makes multi-screen possible
|
||||
- [Copper Programming](../08_graphics/copper_programming.md) — writing Copper lists
|
||||
- [Views](../08_graphics/views.md) — View/ViewPort/ViewPortExtra hierarchy
|
||||
- [Bitmap](../08_graphics/bitmap.md) — screen bitmap layout and bitplane organization
|
||||
- [Windows](windows.md) — windows live on screens
|
||||
- [IDCMP](idcmp.md) — input event delivery to windows
|
||||
- [Display Modes](../08_graphics/display_modes.md) — resolution, color depth, and special modes
|
||||
- [RTG Programming](../08_graphics/rtg_programming.md) — graphics card screens
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Amiga devices are shared libraries with an exec I/O request interface. They prov
|
|||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| [trackdisk.md](trackdisk.md) | Floppy disk DMA: MFM encoding, track format, disk geometry, track caching, direct HW access |
|
||||
| [trackdisk.md](trackdisk.md) | Floppy disk DMA: MFM encoding, track format, disk geometry, track caching, direct HW access, 16-command reference, antipatterns, FPGA/MiSTer impact, 6 FAQ |
|
||||
| [scsi.md](scsi.md) | Hard disk/CD-ROM I/O: per-model interfaces, Gayle bandwidth limits, native vs vendor drivers, HD_SCSICMD, CD-ROM commands, TD64/NSD 64-bit |
|
||||
| [serial.md](serial.md) | UART/RS-232: CIA registers, baud rate calculation, serial debugging (KPrintF) |
|
||||
| [parallel.md](parallel.md) | Centronics parallel port: CIA-A Port B mapping, hardware pinout, direct register access |
|
||||
|
|
@ -17,4 +17,4 @@ Amiga devices are shared libraries with an exec I/O request interface. They prov
|
|||
| [keyboard.md](keyboard.md) | CIA-A serial handshake, raw key codes, key matrix, reset sequence, FPGA protocol notes |
|
||||
| [gameport.md](gameport.md) | Joystick/mouse port: quadrature decoding, XOR state, fire buttons, controller types |
|
||||
| [input.md](input.md) | Input handler chain: priority dispatch, event classes, key remapping, Commodities Exchange |
|
||||
| [console.md](console.md) | Text terminal I/O: ANSI escape sequences, cursor/color control, raw key events, CON:/RAW: handlers |
|
||||
| [console.md](console.md) | Text terminal I/O: ANSI escape sequences, cursor/color control, raw key events, CON:/RAW: handlers, decision guide, TUI/progress bar cookbooks, antipatterns, pitfalls, 6 FAQ |
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Shared libraries beyond the core exec/dos/graphics/intuition subsystems. These p
|
|||
| [rexxsyslib.md](rexxsyslib.md) | ARexx scripting: hosting ARexx ports, command parsing, sending commands, return codes |
|
||||
| [arexx_integration.md](arexx_integration.md) | ARexx integration guide: exposing app features, dispatch tables, antipatterns, cookbook |
|
||||
| [mathffp.md](mathffp.md) | Motorola FFP and IEEE 754 floating point |
|
||||
| [layers.md](layers.md) | Window clipping: ClipRect engine, Simple/Smart/Super refresh, damage repair, backfill hooks, layer locking |
|
||||
| [layers.md](layers.md) | Window clipping: ClipRect engine, Simple/Smart/Super refresh, damage repair, backfill hooks, layer locking, LVO API reference, 4 antipatterns, ClipBlit vs ScrollRaster optimization, 7 FAQ |
|
||||
| [diskfont.md](diskfont.md) | **Bitmap fonts deep dive: .font file format (FontContentsHeader), font descriptor files (DiskFontHeader), glyph bitmap layout, FONTS: assign, adding/installing fonts, bitmap vs TrueType/OpenType comparison, color fonts (OS 3.0+), Compugraphic outline fonts, AvailFonts enumeration, font loading pipeline** |
|
||||
| [datatypes.md](datatypes.md) | DataTypes system: object-oriented file loading for images, sound, text, animation via BOOPSI classes |
|
||||
| [amigaguide.md](amigaguide.md) | AmigaGuide hypertext help system: database format, @commands, API, ARexx integration, cross-database linking |
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ Development tools for building Amiga software, from native compilers to modern c
|
|||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| [gcc_amiga.md](gcc_amiga.md) | m68k-amigaos-gcc cross-compiler: bebbo's toolchain, Docker setup, CPU targets, libnix/ixemul startup |
|
||||
| [gcc_amiga.md](gcc_amiga.md) | m68k-amigaos-gcc cross-compiler: bebbo's toolchain, Docker setup, platform-specific builds (Linux/macOS/Windows), CPU targets, libnix/ixemul startup, flags, antipatterns, FAQ |
|
||||
| [vbcc.md](vbcc.md) | **VBCC: Volker Barthelmann's portable C compiler — `__reg()` storage class, AmigaOS/MorphOS/AROS targets, vlink integration, cross-compilation** |
|
||||
| [sasc.md](sasc.md) | SAS/C 6.x: pragma format with register encoding, compiler/linker flags, __saveds/__asm idioms, SAS/C vs GCC comparison |
|
||||
| [stormc.md](stormc.md) | StormC native IDE: C/C++ with exceptions, integrated debugger, PowerPC support, version history |
|
||||
|
|
|
|||
6
TODO.md
6
TODO.md
|
|
@ -54,7 +54,7 @@ Articles were scored against [AGENTS.md](../amiga/AGENTS.md) "Deep" criteria:
|
|||
|---|---|---|---|---|
|
||||
| 15 | `08_graphics/sprites.md` | 306 | 306 | ❌ **Pending** — Named antipatterns, pitfalls comparing hardware sprites vs SimpleSprite, FPGA sprite timing |
|
||||
| 16 | `08_graphics/text_fonts.md` | 215 | 708 | ✅ **Complete** — Expanded with ColorTextFont layout, Compugraphic outlines, font scaling/aspect ratio, draw mode effects, 3 cookbooks (centered title, multi-font label, word wrap), 4 antipatterns, 4 pitfalls, historical comparison, modern analogies, 6 FAQ |
|
||||
| 17 | `09_intuition/screens.md` | 582 | 582 | ❌ **Pending** — Antipatterns, cookbook (screen flipping, borderless, PAL→NTSC handling) |
|
||||
| 17 | `09_intuition/screens.md` | 582 | 992 | ✅ **Complete** — Added screen type decision guide (Mermaid), 5 named antipatterns (Orphan Screen, Hardcoded Mode, Stale Pointer, Forced Close, Layer Lock Trap), 3 cookbooks (screen flipping, borderless fullscreen, PAL/NTSC safe), historical comparison, modern analogies, use cases, 7 FAQ |
|
||||
| 18 | `09_intuition/windows.md` | 370 | 778 | ✅ **Complete** — Added 5 named antipatterns (Border Collision, Unresponsive Close, Leaked Message, Refresh Loop, Phantom Window), window type decision guide with Mermaid, 3 cookbooks (resizable, borderless overlay, multi-window shared port), historical comparison, modern analogies, use cases, 7 FAQ |
|
||||
| 19 | `09_intuition/menus.md` | 378 | 695 | ✅ **Complete** — Added render chain sequence diagram, 5 named antipatterns (Multi-Select Ghost, Stale Menu, Cleanup Reversal, Shortcut Collision, Phantom VisualInfo), complete lifecycle cookbook, historical comparison, modern analogies, use cases, 6 FAQ |
|
||||
| 20 | `09_intuition/gadgets.md` | 403 | 804 | ✅ **Complete** — Added 5 named antipatterns (Invisible Gadget, Message Mangler, Orphaned Chain, Hot-Swap Hazard, Silent Button), GadTools→BOOPSI migration guide with comparison table, form cookbook, historical timeline, modern analogies, use cases, 6 FAQ |
|
||||
|
|
@ -267,7 +267,7 @@ Articles were scored against [AGENTS.md](../amiga/AGENTS.md) "Deep" criteria:
|
|||
| `idcmp.md` | 1060 | ✅ Deep | Event architecture, shared ports, antipatterns, cookbook — exemplary |
|
||||
| `input_events.md` | 850 | ✅ Deep | Handler chain, QoS/priority, Commodities, latency analysis |
|
||||
| `commodities.md` | 769 | ✅ Deep | Tier 1 creation: Exchange, hotkeys, CxObjects, brokers |
|
||||
| `screens.md` | 582 | ❌ Pending | Tier 3 #17: needs antipatterns, cookbook (screen flipping, borderless, PAL→NTSC) |
|
||||
| `screens.md` | 992 | ✅ Deep | Decision guide, 5 antipatterns, 3 cookbooks (flipping, borderless, PAL/NTSC), historical + modern analogies, use cases, 7 FAQ |
|
||||
| `boopsi.md` | 505 | ✅ Adequate | OOP dispatcher, ICA interconnection, custom class tutorial |
|
||||
| `gadgets.md` | 804 | ✅ Deep | 5 antipatterns, GadTools→BOOPSI migration, form cookbook, timeline, modern analogies, use cases, 6 FAQ |
|
||||
| `menus.md` | 695 | ✅ Deep | Render chain diagram, 5 antipatterns, lifecycle cookbook, historical + modern analogies, use cases, 6 FAQ |
|
||||
|
|
@ -450,7 +450,7 @@ Articles were scored against [AGENTS.md](../amiga/AGENTS.md) "Deep" criteria:
|
|||
|
||||
| # | File | Current |
|
||||
|---|---|---|
|
||||
| 26 | `05_reversing/custom_loaders_and_drm.md` | 168 lines |
|
||||
| 26 | `05_reversing/custom_loaders_and_drm.md` | 500 lines — ✅ Deep: bootblock structure, 6 DRM systems, 5 antipatterns, trackloader cookbook, cracking scene history, 7 FAQ |
|
||||
| 27 | `08_graphics/rtg_programming.md` | 0 lines |
|
||||
| 28 | `11_libraries/ahi_programming.md` | 0 lines |
|
||||
| 29 | `17_demoscene/README.md` | 0 lines |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue