docs(amiga): complete AmigaOS 3.1/3.2 developer reference — 172 files across 17 sections

Comprehensive technical documentation covering:
- Hardware: OCS/ECS/AGA custom chip registers, Copper & Blitter deep dives
- Boot sequence: cold boot through startup-sequence
- Binary format: HUNK executable spec, relocation, debug info
- Linking & ABI: .fd files, LVO tables, register calling conventions
- Exec kernel: tasks, interrupts, memory, signals, semaphores
- AmigaDOS: file I/O, FFS/OFS layout, CLI/Shell scripting
- Graphics: planar bitmaps, Copper programming, HAM/EHB modes
- Intuition: screens, windows, IDCMP, BOOPSI
- Devices: trackdisk, SCSI, serial, timer, audio, keyboard
- Libraries: utility, expansion, IFFParse, locale, ARexx
- Networking: bsdsocket API, SANA-II, TCP/IP stack comparison
- Toolchain: GCC, vasm/vlink, SAS/C, NDK, debugging
- Reverse engineering: IDA/Ghidra setup, compiler fingerprints, case studies
- CPU & MMU: 68040/060 emulation libs, PMMU, cache management
- Driver development: SANA-II, Picasso96/RTG, AHI audio

All files include breadcrumb navigation. No local paths or proprietary content.
This commit is contained in:
Ilia Sharin 2026-04-23 12:16:52 -04:00
parent f07a368bf1
commit 21751c0025
172 changed files with 19701 additions and 0 deletions

21
08_graphics/README.md Normal file
View file

@ -0,0 +1,21 @@
[← Home](../README.md)
# Graphics Subsystem — Overview
## Section Index
| File | Description |
|---|---|
| [gfx_base.md](gfx_base.md) | GfxBase structure and global graphics state |
| [bitmap.md](bitmap.md) | BitMap structure, planar layout, allocation |
| [copper.md](copper.md) | Copper coprocessor, instruction format, UCopList |
| [blitter.md](blitter.md) | Blitter DMA engine, minterms, BltBitMap |
| [sprites.md](sprites.md) | Hardware sprites, SimpleSprite, MoveSprite |
| [rastport.md](rastport.md) | RastPort, drawing primitives, layers |
| [views.md](views.md) | View, ViewPort, MakeVPort, display construction |
| [text_fonts.md](text_fonts.md) | TextFont, TextAttr, OpenFont, Text rendering |
| [display_modes.md](display_modes.md) | Display database, ModeID, monitor specs |
| [ham_ehb_modes.md](ham_ehb_modes.md) | HAM6, HAM8, and EHB special display modes |
| [animation.md](animation.md) | AnimOb, BOB, VSprite, GEL system |
| [copper_programming.md](copper_programming.md) | Copper deep dive: architecture, examples, system API |
| [blitter_programming.md](blitter_programming.md) | Blitter deep dive: minterms, cookie-cut, line draw |

110
08_graphics/animation.md Normal file
View file

@ -0,0 +1,110 @@
[← Home](../README.md) · [Graphics](README.md)
# Animation — GEL System: BOBs, VSprites, AnimObs
## Overview
The **GEL (Graphics ELement)** system provides high-level animated sprite and bitmap overlay support. It manages VSprites (virtual sprites that can use hardware or software rendering), BOBs (Blitter OBjects — arbitrary-sized bitmaps overlaid on a playfield), and AnimObs (animation objects with sequencing).
---
## VSprite
```c
/* graphics/gels.h — NDK39 */
struct VSprite {
struct VSprite *NextVSprite;
struct VSprite *PrevVSprite;
struct VSprite *DrawPath;
struct VSprite *ClearPath;
WORD OldY, OldX; /* previous position */
WORD Flags; /* VSPRITE, SAVEBACK, OVERLAY, MUSTDRAW */
WORD Y, X; /* current position */
WORD Height;
WORD Width; /* width in words */
WORD Depth;
WORD MeMask; /* collision mask */
WORD HitMask;
WORD *ImageData; /* sprite image */
WORD *BorderLine; /* collision border */
WORD *CollMask; /* collision mask data */
WORD *SprColors; /* colour table */
struct Bob *VSBob; /* if this VSprite backs a BOB */
BYTE PlanePick;
BYTE PlaneOnOff;
/* ... */
};
```
---
## BOB (Blitter Object)
```c
struct Bob {
WORD Flags;
WORD *SaveBuffer; /* background save buffer */
WORD *ImageShadow; /* shadow mask for cookie-cut */
struct Bob *Before;
struct Bob *After;
struct VSprite *BobVSprite; /* associated VSprite */
struct AnimComp *BobComp; /* if part of animation */
struct DBufPacket *DBuffer; /* double-buffer packet */
};
```
---
## Usage Pattern
```c
struct GelsInfo gi;
struct VSprite headVS, tailVS;
/* Initialise GEL system: */
InitGels(&headVS, &tailVS, &gi);
rp->GelsInfo = &gi;
/* Add a VSprite/BOB: */
AddVSprite(&myVSprite, rp);
/* or */
AddBob(&myBob, rp);
/* Each frame: */
SortGList(rp); /* sort by Y position */
DrawGList(rp, &vp); /* render all GELs */
WaitTOF(); /* sync to vertical blank */
/* Cleanup: */
RemVSprite(&myVSprite);
/* or */
RemBob(&myBob);
```
---
## AnimOb — Animation Sequences
```c
struct AnimOb {
struct AnimOb *NextOb;
struct AnimOb *PrevOb;
LONG Clock; /* frame counter */
WORD AnOldY, AnOldX;
WORD AnY, AnX; /* current position */
WORD YVel, XVel; /* velocity */
WORD YAccel, XAccel; /* acceleration */
WORD RingYTrans; /* ring buffer Y translation */
WORD RingXTrans;
struct AnimComp *HeadComp; /* component chain */
/* ... */
};
```
---
## References
- NDK39: `graphics/gels.h`, `graphics/gelsinternal.h`
- ADCD 2.1: `InitGels`, `AddVSprite`, `AddBob`, `SortGList`, `DrawGList`
- *Amiga ROM Kernel Reference Manual: Libraries* — GELs chapter

117
08_graphics/bitmap.md Normal file
View file

@ -0,0 +1,117 @@
[← Home](../README.md) · [Graphics](README.md)
# BitMap — Planar Bitmap Structure and Layout
## Overview
Amiga display memory uses **planar** layout: each bitplane is a separate contiguous memory region. A pixel's colour index is formed by reading one bit from each plane at the same x,y position. This is fundamentally different from chunky (packed-pixel) or interleaved formats.
---
## struct BitMap
```c
/* graphics/gfx.h — NDK39 */
struct BitMap {
UWORD BytesPerRow; /* bytes per row per plane (must be even) */
UWORD Rows; /* height in pixels */
UBYTE Flags; /* BMF_* flags */
UBYTE Depth; /* number of bitplanes (18) */
UWORD pad;
PLANEPTR Planes[8]; /* pointers to each bitplane buffer */
};
```
---
## BMF_ Flags
```c
#define BMF_CLEAR (1<<0) /* clear planes on allocation */
#define BMF_DISPLAYABLE (1<<1) /* allocated in displayable (Chip) RAM */
#define BMF_INTERLEAVED (1<<2) /* planes are interleaved in memory */
#define BMF_STANDARD (1<<3) /* use standard allocation */
#define BMF_MINPLANES (1<<4) /* minimum number of planes */
```
---
## Planar Memory Layout
For a 320×256×4 display (16 colours):
```
BytesPerRow = 320/8 = 40 bytes
Rows = 256
Depth = 4
Plane 0: 40 × 256 = 10,240 bytes (bit 0 of colour index)
Plane 1: 40 × 256 = 10,240 bytes (bit 1)
Plane 2: 40 × 256 = 10,240 bytes (bit 2)
Plane 3: 40 × 256 = 10,240 bytes (bit 3)
Total = 4 × 10,240 = 40,960 bytes
```
Pixel colour at (x, y):
```
bit0 = (Planes[0][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
bit1 = (Planes[1][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
bit2 = (Planes[2][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
bit3 = (Planes[3][y * BytesPerRow + x/8] >> (7 - x%8)) & 1
colour_index = (bit3 << 3) | (bit2 << 2) | (bit1 << 1) | bit0
```
---
## Allocation
```c
/* OS 3.0+ — AllocBitMap: */
struct BitMap *bm = AllocBitMap(320, 256, 4,
BMF_CLEAR | BMF_DISPLAYABLE, NULL);
/* Always in Chip RAM when BMF_DISPLAYABLE */
/* Manual allocation (OS 1.x compatible): */
struct BitMap bm;
InitBitMap(&bm, 4, 320, 256);
for (int i = 0; i < 4; i++)
bm.Planes[i] = AllocRaster(320, 256); /* MEMF_CHIP */
/* Free: */
FreeBitMap(bm); /* or FreeRaster per plane */
```
---
## Interleaved BitMaps
With `BMF_INTERLEAVED`, all planes are stored sequentially row by row:
```
Row 0, Plane 0: 40 bytes
Row 0, Plane 1: 40 bytes
Row 0, Plane 2: 40 bytes
Row 0, Plane 3: 40 bytes
Row 1, Plane 0: 40 bytes
...
```
BytesPerRow becomes `40 × Depth = 160`, and each `Planes[i]` pointer is offset by `i * 40` from the base. This layout is more cache-friendly and allows single-pass blits.
---
## AGA 8-Bit Bitmaps
AGA (A1200/A4000) supports up to 8 bitplanes = 256 colours:
```c
struct BitMap *bm = AllocBitMap(320, 256, 8, BMF_CLEAR | BMF_DISPLAYABLE, NULL);
/* 8 planes × 10,240 = 81,920 bytes of Chip RAM */
```
---
## References
- NDK39: `graphics/gfx.h`
- ADCD 2.1: `AllocBitMap`, `FreeBitMap`, `InitBitMap`
- HRM: *Amiga Hardware Reference Manual* — bitplane DMA chapter

109
08_graphics/blitter.md Normal file
View file

@ -0,0 +1,109 @@
[← Home](../README.md) · [Graphics](README.md)
# Blitter — DMA Engine, Minterms, BltBitMap
## Overview
The **Blitter** is a DMA engine in the custom chips that performs bulk memory operations: block copies, line drawing, area fills, and arbitrary boolean combinations of up to three source bitmaps. It operates independently of the CPU, freeing the 68k for other work.
---
## Channels
The blitter has four DMA channels:
| Channel | Name | Direction | Description |
|---|---|---|---|
| A | Source A | Read | First source bitmap |
| B | Source B | Read | Second source (often mask/pattern) |
| C | Source C | Read | Third source (typically destination for read-modify-write) |
| D | Destination | Write | Output |
Each channel has: pointer register, modulo register, shift register (A/B only), and first/last word masks (A only).
---
## Minterm Logic
The blitter combines A, B, C inputs using an 8-bit **minterm** value. Each bit selects whether the output is 1 for a specific combination:
| Bit | A | B | C | Common Use |
|---|---|---|---|---|
| 7 | 1 | 1 | 1 | — |
| 6 | 1 | 1 | 0 | — |
| 5 | 1 | 0 | 1 | — |
| 4 | 1 | 0 | 0 | — |
| 3 | 0 | 1 | 1 | — |
| 2 | 0 | 1 | 0 | — |
| 1 | 0 | 0 | 1 | — |
| 0 | 0 | 0 | 0 | — |
Common minterm values:
| Minterm | Hex | Operation |
|---|---|---|
| `$F0` | `A` | Copy A to D (straight copy) |
| `$CA` | `AB + ~AC` | Cookie-cut: A=mask, B=source, C=background |
| `$3C` | `A XOR C` | XOR blit (sprite toggle) |
| `$0F` | `NOT A` | Invert source |
| `$00` | `0` | Clear destination |
| `$FF` | `1` | Fill destination with 1s |
---
## Register Map
| Address | Name | Description |
|---|---|---|
| `$DFF040` | `BLTCON0` | Control: use-channels + minterm + shift-A |
| `$DFF042` | `BLTCON1` | Control: direction, fill mode, line mode |
| `$DFF044` | `BLTAFWM` | First word mask for channel A |
| `$DFF046` | `BLTALWM` | Last word mask for channel A |
| `$DFF048` | `BLTCPT` | Channel C pointer (high word) |
| `$DFF04A` | `BLTCPT` | Channel C pointer (low word) |
| `$DFF04C` | `BLTBPT` | Channel B pointer |
| `$DFF050` | `BLTAPT` | Channel A pointer |
| `$DFF054` | `BLTDPT` | Channel D pointer (destination) |
| `$DFF058` | `BLTSIZE` | Size and start: `(height << 6) | width_words` |
| `$DFF064` | `BLTCMOD` | Channel C modulo |
| `$DFF062` | `BLTBMOD` | Channel B modulo |
| `$DFF060` | `BLTAMOD` | Channel A modulo |
| `$DFF066` | `BLTDMOD` | Channel D modulo |
---
## OS-Level Blitter Functions
```c
/* graphics.library */
/* Copy rectangular region between bitmaps: */
LONG BltBitMap(
struct BitMap *srcBM, WORD srcX, WORD srcY,
struct BitMap *dstBM, WORD dstX, WORD dstY,
WORD sizeX, WORD sizeY,
UBYTE minterm, /* usually $C0 = copy */
UBYTE mask, /* plane mask */
APTR tempA /* temp buffer or NULL */
);
/* Blit into RastPort (clips to layer): */
void BltBitMapRastPort(struct BitMap *src, WORD srcX, WORD srcY,
struct RastPort *rp, WORD dstX, WORD dstY,
WORD sizeX, WORD sizeY, UBYTE minterm);
/* Wait for blitter completion: */
void WaitBlit(void); /* must call before freeing blit buffers */
/* Gain exclusive blitter access: */
void OwnBlitter(void);
void DisownBlitter(void);
```
---
## References
- HRM: *Amiga Hardware Reference Manual* — Blitter chapter
- NDK39: `hardware/blit.h`, `graphics/gfx.h`
- ADCD 2.1: `BltBitMap`, `BltBitMapRastPort`, `OwnBlitter`

View file

@ -0,0 +1,257 @@
[← Home](../README.md) · [Graphics](README.md)
# Blitter Programming — Deep Dive
## Overview
The **Blitter** (Block Image Transfer) is a DMA engine that performs raster operations on rectangular blocks of memory. It operates on up to **4 channels** (A, B, C → D) using programmable **minterm logic** and can work independently of the CPU. The Blitter is the workhorse for screen clearing, scrolling, cookie-cut sprites, line drawing, and area fill.
---
## Channel Architecture
```
Channel A ──→ ┐
Channel B ──→ ├──→ Minterm Logic ──→ Channel D (output)
Channel C ──→ ┘
A = mask/pattern (e.g., cookie shape, font glyph)
B = source image data
C = background / destination read-back
D = output destination
```
Each channel reads (or writes, for D) from a different memory pointer with independent modulo.
---
## Minterm Logic
The minterm is an **8-bit truth table** encoding the logical function of A, B, C:
```
Bit 7: ABC = 111 → bit value
Bit 6: ABC = 110 → bit value
Bit 5: ABC = 101 → bit value
Bit 4: ABC = 100 → bit value
Bit 3: ABC = 011 → bit value
Bit 2: ABC = 010 → bit value
Bit 1: ABC = 001 → bit value
Bit 0: ABC = 000 → bit value
```
### Common Minterms
| Minterm | Hex | Operation | Use Case |
|---|---|---|---|
| `D = A` | `$F0` | Copy A to D | Simple block copy |
| `D = B` | `$CC` | Copy B to D | Simple block copy |
| `D = C` | `$AA` | Copy C to D | Read-back |
| `D = A·B + (¬A)·C` | `$CA` | Cookie-cut | Masked sprite blit (B through A mask onto C) |
| `D = 0` | `$00` | Clear | Clear a memory region |
| `D = $FFFF` | `$FF` | Set all | Fill with 1s |
| `D = A XOR C` | `$5A` | XOR | Cursor blink, highlight |
| `D = A OR C` | `$FA` | OR | Overlay |
| `D = ¬A AND C` | `$0A` | Mask out | Erase through mask |
| `D = A·B` | `$C0` | AND (A,B) | Masked pattern |
### Cookie-Cut Explained
```
A = mask (1 = sprite pixel, 0 = transparent)
B = sprite image data
C = background
D = result
Minterm $CA:
Where A=1: D = B (show sprite)
Where A=0: D = C (show background)
```
---
## Register Reference
| Reg | Offset | Description |
|---|---|---|
| `BLTCON0` | `$040` | Control: channels enabled (bits 118), ASH (bits 1512), minterm (bits 70) |
| `BLTCON1` | `$042` | Control: BSH (bits 1512), line mode (bit 0), fill mode (bits 32) |
| `BLTAFWM` | `$044` | First word mask for channel A |
| `BLTALWM` | `$046` | Last word mask for channel A |
| `BLTAPT` | `$050` | Channel A pointer (high+low) |
| `BLTBPT` | `$04C` | Channel B pointer |
| `BLTCPT` | `$048` | Channel C pointer |
| `BLTDPT` | `$054` | Channel D pointer |
| `BLTAMOD` | `$064` | Channel A modulo |
| `BLTBMOD` | `$062` | Channel B modulo |
| `BLTCMOD` | `$060` | Channel C modulo |
| `BLTDMOD` | `$066` | Channel D modulo |
| `BLTSIZE` | `$058` | Blit size + START (write triggers blit) |
### BLTCON0 Encoding
```
Bits 1512: ASH (A shift, 015 pixels)
Bit 11: USEA (enable channel A)
Bit 10: USEB (enable channel B)
Bit 9: USEC (enable channel C)
Bit 8: USED (enable channel D, almost always 1)
Bits 70: Minterm
```
### BLTSIZE Encoding (OCS/ECS)
```
Bits 156: Height in lines (11024, 0 means 1024)
Bits 50: Width in words (164, 0 means 64)
```
**Writing BLTSIZE starts the blit!**
---
## Complete Examples
### Example 1: Clear Screen (320×256, 1 bitplane)
```asm
lea $DFF000,a5
; Wait for blitter idle:
.bwait:
btst #14,$002(a5) ; DMACONR bit 14 = BBUSY
bne.s .bwait
; D channel only, minterm $00 (clear):
move.l #$01000000,$040(a5) ; BLTCON0: USED=1, minterm=$00
clr.w $042(a5) ; BLTCON1: 0
move.l #ScreenMem,$054(a5) ; BLTDPT
clr.w $066(a5) ; BLTDMOD: 0 (contiguous)
move.w #(256<<6)|20,$058(a5) ; BLTSIZE: 256 lines × 20 words (320/16)
; Blit is now running!
```
### Example 2: Block Copy (No Shift)
```asm
; Copy 64×64 pixel block from source to dest (1 bitplane)
; Source and dest are in contiguous bitmap, 320 pixels wide
; Width = 64 pixels = 4 words
; Modulo = (320 - 64) / 16 = 16 words = 32 bytes
lea $DFF000,a5
.bwait:
btst #14,$002(a5)
bne.s .bwait
move.l #$09F00000,$040(a5) ; BLTCON0: USEA+USED, minterm=$F0 (A→D)
clr.w $042(a5) ; BLTCON1
move.w #$FFFF,$044(a5) ; BLTAFWM = all bits
move.w #$FFFF,$046(a5) ; BLTALWM = all bits
move.l #SourceAddr,$050(a5) ; BLTAPT
move.l #DestAddr,$054(a5) ; BLTDPT
move.w #32,$064(a5) ; BLTAMOD = 32 bytes
move.w #32,$066(a5) ; BLTDMOD = 32 bytes
move.w #(64<<6)|4,$058(a5) ; BLTSIZE: 64 lines × 4 words GO!
```
### Example 3: Cookie-Cut Blit (Masked Sprite)
```asm
; Blit a 16×16 masked sprite onto background
; A = mask, B = sprite data, C = background, D = destination
lea $DFF000,a5
.bwait:
btst #14,$002(a5)
bne.s .bwait
move.l #$0FCA0000,$040(a5) ; BLTCON0: A+B+C+D, minterm=$CA
clr.w $042(a5) ; BLTCON1
move.w #$FFFF,$044(a5) ; BLTAFWM
move.w #$FFFF,$046(a5) ; BLTALWM
move.l #MaskData,$050(a5) ; BLTAPT = mask
move.l #SpriteData,$04C(a5) ; BLTBPT = sprite imagery
move.l #ScreenPos,$048(a5) ; BLTCPT = background (read-back)
move.l #ScreenPos,$054(a5) ; BLTDPT = same as C (overwrite)
clr.w $064(a5) ; BLTAMOD = 0 (mask is 16px = 1 word wide)
clr.w $062(a5) ; BLTBMOD = 0
move.w #38,$060(a5) ; BLTCMOD = (320-16)/8 = 38 bytes
move.w #38,$066(a5) ; BLTDMOD = 38
move.w #(16<<6)|1,$058(a5) ; BLTSIZE: 16 lines × 1 word GO!
```
### Example 4: Line Drawing
```asm
; Draw a line from (x1,y1) to (x2,y2) using blitter line mode
; This is complex — blitter line mode uses a Bresenham-style algorithm
; implemented in hardware
; BLTCON1 bit 0 = LINE mode
; Channel A = single word (texture pattern)
; Channel C/D = destination bitmap
; See HRM for the full algorithm; here's the concept:
move.l #$0B4A0000,$040(a5) ; BLTCON0: A+C+D, minterm=$4A (XOR), ASH=dx
move.w #$0001,$042(a5) ; BLTCON1: LINE=1, octant bits set per slope
move.w #$8000,$074(a5) ; BLTADAT: single pixel pattern
move.w #$FFFF,$044(a5) ; BLTAFWM
move.l #StartPos,$048(a5) ; BLTCPT: line start position in bitmap
move.l #StartPos,$054(a5) ; BLTDPT: same
move.w #Modulo,$060(a5) ; BLTCMOD
move.w #Modulo,$066(a5) ; BLTDMOD
move.w #(len<<6)|2,$058(a5) ; BLTSIZE: length × 2 GO!
```
---
## System-Friendly Blitter (via graphics.library)
```c
/* BltBitMap — the safe, OS-friendly way: */
BltBitMap(srcBitmap, srcX, srcY,
dstBitmap, dstX, dstY,
width, height,
0xC0, /* minterm: A AND B */
0xFF, /* all planes */
NULL); /* temp buffer */
/* BltMaskBitMapRastPort — cookie-cut with mask: */
BltMaskBitMapRastPort(srcBM, srcX, srcY,
rp, dstX, dstY,
width, height,
(ABC | ABNC | ANBC), /* minterm for cookie */
maskPlane);
/* BltClear — fast memory clear: */
BltClear(memory, byteCount, 0);
/* OwnBlitter / DisownBlitter — exclusive access: */
OwnBlitter(); /* wait for and lock blitter */
/* ... direct register programming ... */
DisownBlitter(); /* release */
```
---
## Performance Notes
| Operation | Speed |
|---|---|
| Word copy | 4 DMA cycles per word (1 µs at 3.58 MHz) |
| Full 320×256 clear | ~1280 µs (~1.3 ms) |
| Cookie-cut blit | 4 channels = 4 cycles/word (same as copy) |
| CPU vs blitter | Blitter wins for moves > ~40 words |
| Nasty mode | `BLTPRI` in DMACON: blitter gets priority, CPU stalls |
---
## References
- HRM: *Blitter* chapter — complete register descriptions
- `01_hardware/ocs_a500/blitter.md` — hardware reference
- `08_graphics/blitter.md` — graphics.library BltBitMap API

124
08_graphics/copper.md Normal file
View file

@ -0,0 +1,124 @@
[← Home](../README.md) · [Graphics](README.md)
# Copper — Coprocessor Instructions and UCopList
## Overview
The **Copper** is a simple coprocessor in the Amiga custom chips that executes a list of instructions synchronised to the video beam. It can write to any custom chip register at any beam position, enabling per-scanline colour changes, split screens, and hardware-level display effects without CPU intervention.
---
## Instruction Format
The Copper has only three instructions, each 32 bits (one longword):
### MOVE — Write a Register
```
[register_offset (9 bits)] [value (16 bits)]
Bit layout: 0RRRRRRRR00000000 VVVVVVVVVVVVVVVV
```
- Register offset is relative to `$DFF000` (custom chip base)
- Only even registers can be written (bit 0 = 0)
- Example: `$0180, $0FFF` → write `$0FFF` to `COLOR00` (`$DFF180`)
### WAIT — Wait for Beam Position
```
[vpos (8 bits)] [hpos (7 bits)] [1] [vmask (7 bits)] [hmask (7 bits)] [0]
Bit layout: VVVVVVVVHHHHHH01 vvvvvvvvhhhhhhh0
```
- Pauses until the beam reaches at least the specified (vpos, hpos)
- Masks allow waiting on partial positions (e.g. any horizontal, specific vertical)
### SKIP — Conditional Skip
```
Same as WAIT but bit 0 of second word = 1
```
If the beam has already passed the specified position, skip the next instruction.
---
## Standard Copper Patterns
### Per-Scanline Colour Change (Rainbow)
```
WAIT $2C01,$FFFE ; wait for line $2C (44)
MOVE $0180,$0F00 ; COLOR00 = red
WAIT $2D01,$FFFE ; wait for line $2D (45)
MOVE $0180,$00F0 ; COLOR00 = green
WAIT $2E01,$FFFE ; wait for line $2E (46)
MOVE $0180,$000F ; COLOR00 = blue
...
WAIT $FFDF,$FFFE ; wait past line 255 (enables access to lines 256+)
WAIT $FFFF,$FFFE ; end-of-list (impossible position = halt)
```
### End of Copper List
```
$FFFF, $FFFE ; WAIT for beam position $FFFF — never reached
```
This is the standard "stop" marker. The Copper loops back to the start on the next vertical blank.
---
## System Copper Lists
The OS manages copper lists through `GfxBase`:
| Pointer | Description |
|---|---|
| `GfxBase->copinit` | System initialisation copper list |
| `GfxBase->LOFlist` | Long-frame copper list (even fields) |
| `GfxBase->SHFlist` | Short-frame copper list (odd fields, interlace) |
---
## UCopList — User Copper Instructions
Applications can inject copper instructions into the system list via `UCopList`:
```c
struct UCopList *ucl = AllocMem(sizeof(struct UCopList), MEMF_PUBLIC|MEMF_CLEAR);
CINIT(ucl, 100); /* init, max 100 instructions */
CWAIT(ucl, 44, 0); /* wait for line 44 */
CMOVE(ucl, *((UWORD *)0xDFF180), 0x0F00); /* COLOR00 = red */
CWAIT(ucl, 100, 0);
CMOVE(ucl, *((UWORD *)0xDFF180), 0x000F); /* COLOR00 = blue */
CEND(ucl); /* end of list */
viewport->UCopIns = ucl;
RethinkDisplay(); /* rebuild system copper list */
```
---
## Custom Chip Register Addresses (Copper-Relevant)
| Address | Name | Description |
|---|---|---|
| `$DFF180``$DFF1BE` | `COLOR00``COLOR31` | OCS/ECS palette (12-bit RGB) |
| `$DFF100` | `BPLCON0` | Bitplane control (depth, resolution) |
| `$DFF102` | `BPLCON1` | Scroll offsets |
| `$DFF104` | `BPLCON2` | Priority control |
| `$DFF08E` | `DIWSTRT` | Display window start |
| `$DFF090` | `DIWSTOP` | Display window stop |
| `$DFF092` | `DDFSTRT` | Data fetch start |
| `$DFF094` | `DDFSTOP` | Data fetch stop |
| `$DFF0E0``$DFF0FE` | `BPL1PT``BPL8PT` | Bitplane pointers |
---
## References
- HRM: *Amiga Hardware Reference Manual* — Copper chapter
- NDK39: `graphics/copper.h`, `graphics/gfxmacros.h`
- ADCD 2.1: `CINIT`, `CMOVE`, `CWAIT`, `CEND`

View file

@ -0,0 +1,319 @@
[← Home](../README.md) · [Graphics](README.md)
# Copper Programming — Deep Dive
## What Is the Copper?
The **Copper** (Co-Processor) is a tiny DMA-driven programmable engine inside Agnus (OCS/ECS) or Alice (AGA). It executes a list of instructions — the **copper list** — in lockstep with the video beam as it sweeps across the CRT. Its sole purpose is to write values to custom chip registers at precise screen positions.
Despite having only **3 instructions** and no arithmetic, branching, or memory read capability, the Copper is what gives the Amiga its distinctive visual character.
### Where It Lives in the System
```mermaid
graph LR
subgraph Agnus/Alice ["Agnus / Alice Chip"]
Copper["Copper<br/>(reads copper list via DMA)"]
DMA["DMA Controller"]
Beam["Beam Counter"]
end
subgraph Denise/Lisa ["Denise / Lisa Chip"]
Palette["Colour Registers"]
BPL["Bitplane Control"]
SPR["Sprite Control"]
end
subgraph Memory
CopList["Copper List<br/>(Chip RAM only!)"]
end
Beam -- "current V,H position" --> Copper
CopList -- "DMA fetch" --> Copper
Copper -- "register writes" --> Palette
Copper -- "register writes" --> BPL
Copper -- "register writes" --> SPR
Copper -- "register writes" --> DMA
```
**Key points:**
- The Copper reads its program from **Chip RAM** via DMA — no CPU involvement
- It writes directly to custom chip registers (the same `$DFF000$DFF1FE` space)
- It synchronises with the **beam counter** — it knows exactly where the electron beam is
- The CPU can modify the copper list in memory at any time; changes take effect next frame
### What the Copper Can Do
| Capability | How | Typical Use |
|---|---|---|
| **Per-line colour changes** | WAIT for line → MOVE to COLORxx | Gradient skies, rainbow bars, water effects |
| **Split-screen displays** | Change bitplane pointers mid-frame | Status bar + scrolling game area |
| **Parallax scrolling** | Change BPLCON1 scroll offset at different lines | Multi-layer side-scrollers |
| **Resolution mixing** | Change BPLCON0 mid-frame | HiRes title bar + LoRes gameplay |
| **Sprite multiplexing** | Repoint sprite DMA pointers after sprite ends | 24+ sprites using 8 physical slots |
| **Palette animation** | CPU modifies copper list words each frame | Cycling water, fire, lava |
| **Display window shaping** | Change DIWSTRT/DIWSTOP | Overscan, borders, letterbox |
| **DMA scheduling** | Enable/disable bitplane/sprite DMA per line | Hide artifacts during setup |
### What the Copper Cannot Do
| Limitation | Detail |
|---|---|
| No arithmetic | Cannot add, subtract, multiply, or compare values |
| No branching/loops | Executes linearly top-to-bottom; no jumps or calls |
| No memory read | Can only WRITE to registers — cannot read anything |
| No CPU memory access | Writes only to custom chip registers (`$DFF000`+), not RAM or CIA |
| No sub-pixel timing | Horizontal resolution: 4 colour clocks (~8 low-res pixels) |
| V counter wraps at 255 | PAL lines 256311 require a double-WAIT trick |
| Chip RAM only | The copper list itself must reside in Chip RAM (DMA-accessible) |
### How the System Uses It
**AmigaOS** — `graphics.library` builds the system copper list automatically when you call `MakeVPort()` / `LoadView()`. This list sets up bitplane pointers, sprite pointers, display window, and palette for every ViewPort. User code adds instructions via `UCopList`.
**Games (system takeover)** — Disable the OS display system, point COP1LC to your own copper list, and have total control. The copper list typically sets up the display, changes colours per line, and handles sprite multiplexing.
**Demos** — Push the Copper to its limits: hundreds of colour changes per frame, dynamic copper list generation, and tricks like "copper bars" (changing colours mid-scanline using horizontal WAITs).
---
## Instruction Set
The Copper has exactly **3 instructions**, each 32 bits (2 words):
### MOVE — Write to Register
```
Word 1: RRRRRRRR R0000000 R = register address (9 bits)
Word 2: DDDDDDDD DDDDDDDD D = 16-bit data value
Constraints:
- Register address must be even ($000$1FE range)
- Registers below COPCON threshold ($040) are protected by default
- COPCON ($02E) bit 1 can unlock dangerous registers ($000$03E)
```
**Example:** Set COLOR00 to red
```
dc.w $0180, $0F00 ; MOVE $0F00 → COLOR00 ($DFF180)
```
### WAIT — Wait for Beam Position
```
Word 1: VVVVVVVV HHHHHHHH V = vertical pos (8 bits), H = horizontal pos
Word 2: MMMMMMMM MMMMMM01 M = mask bits, bit 0 = 1 (WAIT marker)
If bit 15 of word 2 is 0: also blitter-finished wait
Default mask: $FFFE (match all V and H bits except bit 0)
```
**Example:** Wait for line 100, any horizontal position
```
dc.w $6401, $FFFE ; WAIT V=$64 (100), H=$01
```
### SKIP — Conditional Skip
```
Word 1: VVVVVVVV HHHHHHHH same format as WAIT
Word 2: MMMMMMMM MMMMMM11 bit 0 = 1, bit 1 = 1 (SKIP marker)
If beam position ≥ specified position, skip next instruction.
```
---
## Beam Position Encoding
```
Vertical: bits 158 of word 1 = V7V0 (range 0255)
For PAL lines > 255, use WAIT twice or the LOF bit
Horizontal: bits 71 of word 1 = H8H1 (range 0$E2, step 2)
Bit 0 always 0 in WAIT word 1 (distinguishes from MOVE)
Full PAL: 312 lines, but copper V wraps at 256
Lines 0255: V = line number
Lines 256+: V wraps; use two WAITs:
WAIT for V=$FF (end of first field)
WAIT for actual line - 256
```
---
## Copper List Termination
```
; End-of-list sentinel (wait for impossible position):
dc.w $FFFF, $FFFE ; WAIT $FF,$FF — never reached
```
---
## Complete Examples
### Example 1: Rainbow Bars (Colour Per Scanline)
```asm
; copperlist.s — 256-colour rainbow using Copper
SECTION copperlist,DATA_C ; MUST be in Chip RAM!
CopperList:
; Set up a basic display first
dc.w $0100, $1200 ; BPLCON0: 1 bitplane, colour on
dc.w $0092, $0038 ; DDFSTRT
dc.w $0094, $00D0 ; DDFSTOP
dc.w $008E, $2C81 ; DIWSTRT
dc.w $0090, $2CC1 ; DIWSTOP
; Line 44 ($2C): start of visible display
dc.w $2C01, $FFFE ; WAIT line 44
dc.w $0180, $0F00 ; COLOR00 = bright red
dc.w $2D01, $FFFE ; WAIT line 45
dc.w $0180, $0E10 ; COLOR00 = red-orange
dc.w $2E01, $FFFE ; WAIT line 46
dc.w $0180, $0D20 ; COLOR00 = orange
dc.w $2F01, $FFFE ; WAIT line 47
dc.w $0180, $0C30 ; COLOR00 = yellow-orange
; ... repeat for each line with incrementing colours ...
dc.w $FFFF, $FFFE ; end of copper list
SECTION code,CODE
start:
move.l 4.w,a6 ; SysBase
lea $DFF000,a5 ; custom chips base
; Install copper list:
move.l #CopperList,$080(a5) ; COP1LCH/COP1LCL
move.w #0,$088(a5) ; COPJMP1 — strobe to restart
; Enable DMA:
move.w #$8280,$096(a5) ; DMACON: SET + COPEN + DMAEN
.wait:
btst #6,$BFE001 ; left mouse button
bne.s .wait
rts
```
### Example 2: Split Screen (Two Different Backgrounds)
```asm
SplitCopperList:
; Top half: blue background
dc.w $0180, $000F ; COLOR00 = blue
; Wait for middle of screen (line 128)
dc.w $8001, $FFFE ; WAIT line $80 = 128
; Bottom half: green background
dc.w $0180, $00F0 ; COLOR00 = green
dc.w $FFFF, $FFFE ; end
```
### Example 3: Parallax Scrolling via Copper
```asm
ParallaxCopperList:
; Background layer: scroll position 0
dc.w $0102, $0000 ; BPLCON1 = no scroll
; Wait for horizon line
dc.w $6001, $FFFE ; WAIT line 96
; Middle layer: scroll by 2 pixels
dc.w $0102, $0022 ; BPLCON1 = scroll 2px both playfields
; Wait for ground layer
dc.w $A001, $FFFE ; WAIT line 160
; Ground layer: scroll by 4 pixels
dc.w $0102, $0044 ; BPLCON1 = scroll 4px
dc.w $FFFF, $FFFE
```
---
## System-Friendly Copper (via graphics.library)
For programs that coexist with the OS:
```c
#include <graphics/copper.h>
/* Allocate a user copper list: */
struct UCopList *ucl = AllocMem(sizeof(struct UCopList), MEMF_CLEAR);
/* Build instructions: */
CINIT(ucl, 100); /* init, max 100 instructions */
CWAIT(ucl, 0, 0); /* wait for top of display */
CMOVE(ucl, custom.color[0], 0x00F); /* set COLOR00 = blue */
CWAIT(ucl, 128, 0); /* wait for line 128 */
CMOVE(ucl, custom.color[0], 0x0F0); /* set COLOR00 = green */
CEND(ucl); /* end */
/* Install on ViewPort: */
vp->UCopIns = ucl;
RethinkDisplay(); /* rebuild system copper list with our additions */
/* Cleanup: */
vp->UCopIns = NULL;
RethinkDisplay();
FreeVPortCopLists(vp);
FreeCopList(ucl);
```
---
## Copper Timing
| Item | Cycles |
|---|---|
| Each Copper instruction | 4 colour clocks (= 8 low-res pixels) |
| WAIT resolution (horizontal) | 4 colour clocks minimum |
| Maximum instructions per line | ~112 (NTSC) / ~114 (PAL) |
| PAL visible lines | 256 (lines 44300) |
| NTSC visible lines | 200 (lines 44244) |
---
## Advanced Techniques
### Copper-Driven Sprite Multiplexing
Reposition sprites mid-frame to display more than 8 sprites:
```asm
; Display sprite 0 at Y=50
dc.w $3001, $FFFE ; WAIT line 48 (before sprite)
dc.w $0120, SprData1>>16 ; SPR0PTH
dc.w $0122, SprData1&$FFFF ; SPR0PTL
; After sprite 0 finishes at Y=66, reuse for position Y=100
dc.w $6801, $FFFE ; WAIT line 104
dc.w $0120, SprData2>>16 ; SPR0PTH — repoint to different data
dc.w $0122, SprData2&$FFFF ; SPR0PTL
```
### Copper-Driven Palette Animation
```asm
; Animate copper list by modifying colour values each frame
; (DMA reads new values each frame automatically)
; Just update the data words in the copper list in Chip RAM
move.w d0, CopperList+6 ; modify the MOVE data word
```
---
## References
- HRM: *Copper* chapter — complete instruction encoding
- `01_hardware/ocs_a500/copper.md` — register-level reference
- `08_graphics/copper.md` — graphics.library UCopList API

View file

@ -0,0 +1,74 @@
[← Home](../README.md) · [Graphics](README.md)
# Display Modes — Display Database, ModeID, Monitor Specs
## Overview
OS 3.0+ provides a **display database** that abstracts monitor/chipset capabilities. Applications query available modes by `ModeID` rather than hardcoding `HIRES`/`LACE` flags.
---
## ModeID Format
A ModeID is a ULONG:
```
bits 3116: Monitor ID
bits 150: Mode within that monitor
```
| ModeID | Name | Resolution |
|---|---|---|
| `$00000000` | LORES | 320×256 (PAL) / 320×200 (NTSC) |
| `$00008000` | HIRES | 640×256/200 |
| `$00000004` | LORES-LACE | 320×512/400 |
| `$00008004` | HIRES-LACE | 640×512/400 |
| `$00080000` | SUPERHIRES | 1280×256 (ECS+) |
| `$00080004` | SUPERHIRES-LACE | 1280×512 |
| `$00039000` | DBLPAL-LORES | 320×256 (AGA scan-doubled) |
| `$00039004` | DBLPAL-HIRES | 640×256 (AGA) |
| `$00011000` | DBLNTSC-LORES | 320×200 (AGA) |
---
## Querying the Display Database
```c
/* graphics.library 39+ */
ULONG modeID = INVALID_ID;
struct DisplayInfo di;
struct DimensionInfo dims;
while ((modeID = NextDisplayInfo(modeID)) != INVALID_ID) {
if (GetDisplayInfoData(NULL, (UBYTE *)&di, sizeof(di),
DTAG_DISP, modeID)) {
if (GetDisplayInfoData(NULL, (UBYTE *)&dims, sizeof(dims),
DTAG_DIMS, modeID)) {
Printf("ModeID $%08lx: %ldx%ld, %ld colours\n",
modeID,
dims.Nominal.MaxX - dims.Nominal.MinX + 1,
dims.Nominal.MaxY - dims.Nominal.MinY + 1,
1 << di.NotAvailable ? 0 : dims.MaxDepth);
}
}
}
```
---
## Best Mode Selection
```c
ULONG bestMode = BestModeIDA((struct TagItem[]){
{ BIDTAG_NominalWidth, 640 },
{ BIDTAG_NominalHeight, 480 },
{ BIDTAG_Depth, 8 },
{ TAG_DONE, 0 }
});
```
---
## References
- NDK39: `graphics/displayinfo.h`, `graphics/modeid.h`
- ADCD 2.1: `NextDisplayInfo`, `GetDisplayInfoData`, `BestModeIDA`

90
08_graphics/gfx_base.md Normal file
View file

@ -0,0 +1,90 @@
[← Home](../README.md) · [Graphics](README.md)
# GfxBase — Graphics Library Global State
## Overview
`graphics.library` manages all display output, drawing primitives, and custom chip programming. `GfxBase` is the library base containing display state, chip revision info, and the system copper lists.
---
## struct GfxBase (Key Fields)
```c
/* graphics/gfxbase.h — NDK39 */
struct GfxBase {
struct Library LibNode;
struct View *ActiView; /* currently active View */
struct copinit *copinit; /* system copper list init */
LONG *cia; /* CIA base (deprecated) */
LONG *blitter; /* blitter base (deprecated) */
UWORD *LOFlist; /* long-frame copper list pointer */
UWORD *SHFlist; /* short-frame copper list (interlace) */
struct bltnode *blthd; /* blitter queue head */
struct bltnode *blttl; /* blitter queue tail */
struct bltnode *bsblthd;
struct bltnode *bsblttl;
struct Interrupt vbsrv; /* vertical blank server list */
struct Interrupt timsrv;
struct Interrupt bltsrv;
struct List TextFonts; /* system font list */
struct TextFont *DefaultFont; /* default system font */
UWORD Modes; /* current display mode bits */
BYTE VBlankFrequency; /* 50 (PAL) or 60 (NTSC) */
BYTE DisplayFlags; /* PAL/NTSC/GENLOCK flags */
UWORD NormalDisplayColumns;
UWORD NormalDisplayRows;
UWORD MaxDisplayColumn;
UWORD MaxDisplayRow;
UWORD ChipRevBits0; /* chip revision flags */
/* ... many more fields ... */
struct MonitorSpec *monitor_id;
struct List MonitorList;
struct List ModesList; /* display mode database */
UBYTE MemType; /* memory type flags */
/* OS 3.x additions */
APTR ChunkyToPlanarPtr; /* c2p conversion routine */
};
```
---
## Chip Revision Detection
```c
/* graphics/gfxbase.h */
#define GFXB_BIG_BLITS 0 /* big blitter (ECS Agnus) */
#define GFXB_HR_AGNUS 0 /* same — hi-res Agnus */
#define GFXB_HR_DENISE 1 /* ECS Denise (SuperHires, scan-doubling) */
#define GFXB_AA_ALICE 2 /* AGA Alice (A1200/A4000) */
#define GFXB_AA_LISA 3 /* AGA Lisa */
#define GFXB_AA_MLISA 4 /* AGA Lisa (modified) */
#define GFXF_BIG_BLITS (1<<0)
#define GFXF_HR_AGNUS (1<<0)
#define GFXF_HR_DENISE (1<<1)
#define GFXF_AA_ALICE (1<<2)
#define GFXF_AA_LISA (1<<3)
#define GFXF_AA_MLISA (1<<4)
/* Check for AGA: */
if (GfxBase->ChipRevBits0 & GFXF_AA_ALICE) {
/* AGA chipset — 8-bit planar, 256 colours in indexed mode */
}
```
---
## PAL vs NTSC
```c
if (GfxBase->VBlankFrequency == 50) /* PAL: 50Hz, 625 lines */
if (GfxBase->VBlankFrequency == 60) /* NTSC: 60Hz, 525 lines */
```
---
## References
- NDK39: `graphics/gfxbase.h`
- ADCD 2.1: graphics.library autodocs

View file

@ -0,0 +1,134 @@
[← Home](../README.md) · [Graphics](README.md)
# HAM and EHB — Special Display Modes
## Overview
The Amiga offers two unique display modes that squeeze many more colours from limited bitplane hardware: **EHB** (Extra Half-Brite) and **HAM** (Hold-And-Modify). These modes have no direct equivalent on other platforms and are critical for understanding Amiga graphics capability.
---
## EHB — Extra Half-Brite (OCS/ECS/AGA)
### How It Works
Uses **6 bitplanes** (64 possible values):
- Bitplane values 031: index into the 32-colour palette normally
- Bitplane values 3263: display the colour from register (value 32) at **half brightness** (all RGB components halved)
```
Bitplanes 04 → 5-bit colour index (031)
Bitplane 5 → "half brightness" flag
```
### Effective Result
- 32 programmer-defined colours + 32 fixed half-brightness versions = **64 colours**
- Zero additional palette RAM needed
- Useful for shadows and smooth gradients
### Enabling EHB
```c
/* In ViewPort ColorMap: */
/* Simply use 6 bitplanes with no HAM flag */
struct BitMap bm;
InitBitMap(&bm, 6, 320, 256); /* 6 planes */
/* No EXTRA_HALFBRITE flag needed — it's automatic when depth=6 */
```
---
## HAM — Hold-And-Modify (OCS/ECS)
### How It Works
Uses **6 bitplanes**. Each pixel's 6 bits are interpreted as:
| Bits 54 | Meaning | Bits 30 |
|---|---|---|
| `00` | **SET** — index colour register | 4-bit palette index (015) |
| `01` | **MODIFY BLUE** — hold R,G; set B | New blue nibble |
| `10` | **MODIFY RED** — hold G,B; set R | New red nibble |
| `11` | **MODIFY GREEN** — hold R,B; set G | New green nibble |
### Effective Result
- Each pixel can set one of 16 base colours, OR modify one component of the previous pixel's colour
- Theoretical maximum: **4,096 colours** on screen simultaneously
- Practical result: colour fringing at sharp edges (each pixel depends on its left neighbour)
### OCS/ECS Limitations
- Only 16 base colours (SET mode uses 4 bits → 16 palette entries)
- Only 4-bit component modification → 16 levels per channel
- Total colour space: 12-bit (4096 colours)
---
## HAM8 — AGA Enhanced HAM
### How It Works
Uses **8 bitplanes**:
| Bits 76 | Meaning | Bits 50 |
|---|---|---|
| `00` | **SET** — index colour register | 6-bit palette index (063) |
| `01` | **MODIFY BLUE** | 6-bit blue value |
| `10` | **MODIFY RED** | 6-bit red value |
| `11` | **MODIFY GREEN** | 6-bit green value |
### Effective Result
- 64 base colours from the 256-entry palette
- 6-bit component modification → 64 levels per channel
- Total colour space: **18-bit** (262,144 colours)
- Significantly reduced fringing compared to HAM6
### HAM8 Memory Layout
```
8 bitplanes × 320 pixels × 256 lines = 81,920 bytes per plane × 8
= 655,360 bytes (640 KB) for a single HAM8 320×256 display
```
---
## Enabling HAM
```c
/* Via ViewPort: */
vp->Modes |= HAM; /* HAMF flag in modes */
/* Via SA_ tags (Intuition screen): */
struct TagItem scrTags[] = {
{ SA_Width, 320 },
{ SA_Height, 256 },
{ SA_Depth, 6 }, /* 6 for HAM6, 8 for HAM8 */
{ SA_DisplayID, HAM_KEY }, /* or SUPER_KEY|HAM for Super-HiRes HAM */
{ TAG_DONE, 0 }
};
```
---
## Comparison Table
| Feature | EHB | HAM6 | HAM8 |
|---|---|---|---|
| Bitplanes | 6 | 6 | 8 |
| Chipset | OCS/ECS/AGA | OCS/ECS/AGA | AGA only |
| Base palette | 32 | 16 | 64 |
| Max on-screen colours | 64 | 4,096 | 262,144 |
| Colour depth | 12-bit | 12-bit | 24-bit (via 18-bit HAM) |
| Fringing | None | Significant | Mild |
| Good for | GUI, sprites | Photos, static art | Photos, video stills |
| Bad for | — | Animation, scrolling | Memory-hungry |
---
## References
- HRM: *Display modes* chapter
- NDK39: `graphics/displayinfo.h``HAM_KEY`, `EXTRAHALFBRITE_KEY`

112
08_graphics/rastport.md Normal file
View file

@ -0,0 +1,112 @@
[← Home](../README.md) · [Graphics](README.md)
# RastPort — Drawing Primitives and Layers
## Overview
`RastPort` is the primary drawing context in AmigaOS. All graphics primitives (pixel, line, rectangle, polygon, text) operate through a `RastPort`, which links a `BitMap`, drawing pen colours, pattern, font, and optional `Layer` for clipping.
---
## struct RastPort
```c
/* graphics/rastport.h — NDK39 */
struct RastPort {
struct Layer *Layer; /* associated layer (NULL = no clipping) */
struct BitMap *BitMap; /* target bitmap */
UWORD *AreaPtrn; /* area fill pattern */
struct TmpRas *TmpRas; /* temp raster for area fills/floods */
struct AreaInfo *AreaInfo; /* area fill vertex buffer */
struct GelsInfo *GelsInfo; /* GEL (BOB/VSprite) list */
UBYTE Mask; /* plane mask (which planes to draw to) */
BYTE FgPen; /* foreground pen colour index */
BYTE BgPen; /* background pen colour index */
BYTE AOlPen; /* area outline pen */
BYTE DrawMode; /* JAM1, JAM2, COMPLEMENT, INVERSVID */
BYTE AreaPtSz; /* area pattern size (log2) */
BYTE linpatcnt; /* line pattern counter */
BYTE dummy;
UWORD Flags; /* FRST_DOT etc. */
UWORD LinePtrn; /* 16-bit line dash pattern */
WORD cp_x, cp_y; /* current pen position */
UWORD minterms[8];
WORD PenWidth;
WORD PenHeight;
struct TextFont *Font; /* current text font */
UBYTE AlgoStyle; /* algorithmic style flags */
UBYTE TxFlags;
UWORD TxHeight;
UWORD TxWidth;
UWORD TxBaseline;
WORD TxSpacing;
APTR *RP_User;
/* ... */
};
```
---
## Draw Modes
```c
#define JAM1 0 /* draw FgPen only; background transparent */
#define JAM2 1 /* draw FgPen and BgPen (opaque) */
#define COMPLEMENT 2 /* XOR with existing pixels */
#define INVERSVID 4 /* invert video (swap fg/bg for text) */
```
---
## Drawing Primitives
```c
/* Set pen colour: */
SetAPen(rp, 1); /* foreground = colour 1 */
SetBPen(rp, 0); /* background = colour 0 */
SetDrMd(rp, JAM1); /* transparent background */
/* Move to position: */
Move(rp, 100, 50);
/* Draw line from current position to (x,y): */
Draw(rp, 200, 100);
/* Write pixel: */
WritePixel(rp, 160, 120);
/* Read pixel: */
LONG colour = ReadPixel(rp, 160, 120);
/* Filled rectangle: */
RectFill(rp, 10, 10, 100, 50);
/* Draw text at current position: */
Move(rp, 20, 30);
Text(rp, "Hello", 5);
/* Blitter copy between RastPorts: */
ClipBlit(srcRP, sx, sy, dstRP, dx, dy, w, h, minterm);
```
---
## Layers
When `rp->Layer != NULL`, all drawing is clipped to the layer's bounds and damage regions. Layers are managed by `layers.library`:
```c
struct Layer_Info *li = NewLayerInfo();
struct Layer *layer = CreateUpfrontLayer(li, bm, x1, y1, x2, y2, flags, NULL);
rp = layer->rp; /* use this RastPort for drawing */
/* ... draw ... */
DeleteLayer(0, layer);
DisposeLayerInfo(li);
```
---
## References
- NDK39: `graphics/rastport.h`, `graphics/gfxmacros.h`
- ADCD 2.1: `SetAPen`, `Move`, `Draw`, `Text`, `RectFill`, `ClipBlit`

102
08_graphics/sprites.md Normal file
View file

@ -0,0 +1,102 @@
[← Home](../README.md) · [Graphics](README.md)
# Hardware Sprites — SimpleSprite, MoveSprite
## Overview
The Amiga has **8 hardware sprites**, each 16 pixels wide with 3 colours + transparent. Sprites are DMA-driven — the Copper sets their pointers each frame and the display hardware renders them with zero CPU overhead.
---
## Sprite DMA Data Format
Each sprite scanline is two words (4 bytes):
```
Word 0 (DATA): bits 150 = pixel colour bit 0 for this line
Word 1 (DATB): bits 150 = pixel colour bit 1 for this line
Pixel colour = (DATB_bit << 1) | DATA_bit
00 = transparent
01 = colour 1 (from sprite palette)
10 = colour 2
11 = colour 3
```
### Sprite Header
```
WORD 0: VSTART (vertical start position) + HSTART high bits
WORD 1: VSTOP (vertical stop position) + control bits
```
### End marker
```
WORD 0: 0x0000
WORD 1: 0x0000
```
---
## Sprite Colour Palette
| Sprite pair | Colour registers | Custom addresses |
|---|---|---|
| 01 | `COLOR17``COLOR19` | `$DFF1A2``$DFF1A6` |
| 23 | `COLOR21``COLOR23` | `$DFF1AA``$DFF1AE` |
| 45 | `COLOR25``COLOR27` | `$DFF1B2``$DFF1B6` |
| 67 | `COLOR29``COLOR31` | `$DFF1BA``$DFF1BE` |
Sprite pairs can be **attached** to form a single 15-colour sprite (using both sets of 2 bits = 4 bits per pixel).
---
## OS-Level Sprite API
```c
/* graphics.library */
struct SimpleSprite ss;
WORD sprnum;
/* Obtain a free sprite: */
sprnum = GetSprite(&ss, -1); /* -1 = any available */
if (sprnum >= 0) {
ss.x = 100;
ss.y = 50;
ss.height = 16;
/* Move sprite to position: */
MoveSprite(NULL, &ss, 100, 50);
/* Set sprite image data: */
ChangeSprite(NULL, &ss, spriteData);
/* Release: */
FreeSprite(sprnum);
}
```
---
## Sprite Pointer Registers
| Register | Address | Sprite |
|---|---|---|
| `SPR0PTH/L` | `$DFF120$DFF122` | Sprite 0 |
| `SPR1PTH/L` | `$DFF124$DFF126` | Sprite 1 |
| `SPR2PTH/L` | `$DFF128$DFF12A` | Sprite 2 |
| `SPR3PTH/L` | `$DFF12C$DFF12E` | Sprite 3 |
| `SPR4PTH/L` | `$DFF130$DFF132` | Sprite 4 |
| `SPR5PTH/L` | `$DFF134$DFF136` | Sprite 5 |
| `SPR6PTH/L` | `$DFF138$DFF13A` | Sprite 6 |
| `SPR7PTH/L` | `$DFF13C$DFF13E` | Sprite 7 |
These must be set every frame — typically via the Copper list.
---
## References
- HRM: *Amiga Hardware Reference Manual* — Sprites chapter
- NDK39: `graphics/sprite.h`
- ADCD 2.1: `GetSprite`, `MoveSprite`, `ChangeSprite`, `FreeSprite`

90
08_graphics/text_fonts.md Normal file
View file

@ -0,0 +1,90 @@
[← Home](../README.md) · [Graphics](README.md)
# Text and Fonts — TextFont, TextAttr, OpenFont, Text
## Overview
AmigaOS uses bitmap fonts rendered through `graphics.library`. Fonts are described by `TextAttr` (request) and `TextFont` (loaded instance). Disk fonts require `diskfont.library`.
---
## Key Structures
```c
/* graphics/text.h — NDK39 */
struct TextAttr {
STRPTR ta_Name; /* font name, e.g. "topaz.font" */
UWORD ta_YSize; /* desired height in pixels */
UBYTE ta_Style; /* FSF_BOLD, FSF_ITALIC, FSF_UNDERLINED */
UBYTE ta_Flags; /* FPF_ROMFONT, FPF_DISKFONT, etc. */
};
struct TextFont {
struct Message tf_Message;
UWORD tf_YSize; /* font height */
UBYTE tf_Style;
UBYTE tf_Flags;
UWORD tf_XSize; /* nominal width */
UWORD tf_Baseline; /* baseline from top */
UWORD tf_BoldSmear; /* bold smear width */
UWORD tf_Accessors; /* open count */
UBYTE tf_LoChar; /* first character code */
UBYTE tf_HiChar; /* last character code */
APTR tf_CharData; /* bitmap data */
UWORD tf_Modulo; /* bytes per row of font bitmap */
APTR tf_CharLoc; /* character location table */
APTR tf_CharSpace; /* proportional spacing table */
APTR tf_CharKern; /* kerning table */
};
```
---
## Opening Fonts
```c
/* ROM font (topaz, always available): */
struct TextAttr ta = {"topaz.font", 8, 0, FPF_ROMFONT};
struct TextFont *font = OpenFont(&ta);
/* Disk font (requires diskfont.library): */
struct TextAttr ta2 = {"helvetica.font", 24, 0, FPF_DISKFONT};
struct TextFont *font2 = OpenDiskFont(&ta2);
/* Set in RastPort: */
SetFont(rp, font);
```
---
## Rendering Text
```c
Move(rp, 10, 20); /* position cursor */
Text(rp, "Hello Amiga", 11); /* render 11 characters */
/* Get pixel width of a string: */
UWORD width = TextLength(rp, "Hello", 5);
```
---
## Style Flags
```c
#define FSF_UNDERLINED 0x01
#define FSF_BOLD 0x02
#define FSF_ITALIC 0x04
#define FSF_EXTENDED 0x08
/* Set algorithmic style: */
SetSoftStyle(rp, FSF_BOLD | FSF_ITALIC,
AskSoftStyle(rp)); /* ask which styles the font supports */
```
---
## References
- NDK39: `graphics/text.h`
- ADCD 2.1: `OpenFont`, `OpenDiskFont`, `SetFont`, `Text`, `TextLength`

109
08_graphics/views.md Normal file
View file

@ -0,0 +1,109 @@
[← Home](../README.md) · [Graphics](README.md)
# Views and ViewPorts — Display Construction
## Overview
The AmigaOS display system builds the actual screen image through a hierarchy: `View``ViewPort``RasInfo``BitMap`. The `MakeVPort`/`MrgCop`/`LoadView` pipeline compiles this into a Copper list that programs the custom chips.
---
## Key Structures
```c
/* graphics/view.h — NDK39 */
struct View {
struct ViewPort *ViewPort; /* first viewport in chain */
struct cprlist *LOFCprList; /* long-frame copper list */
struct cprlist *SHFCprList; /* short-frame copper list */
WORD DyOffset; /* vertical scroll offset */
WORD DxOffset; /* horizontal scroll offset */
UWORD Modes; /* display mode flags */
};
struct ViewPort {
struct ViewPort *Next; /* next viewport in chain */
struct ColorMap *ColorMap; /* palette for this viewport */
struct CopList *DspIns; /* display copper instructions */
struct CopList *SprIns; /* sprite copper instructions */
struct CopList *ClrIns; /* colour copper instructions */
struct CopList *UCopIns; /* user copper instructions */
WORD DWidth; /* display width */
WORD DHeight; /* display height */
WORD DxOffset;
WORD DyOffset;
UWORD Modes; /* HIRES, LACE, HAM, EHB, etc. */
UBYTE SpritePriorities;
UBYTE ExtendedModes;
struct RasInfo *RasInfo; /* linked bitmap info */
};
struct RasInfo {
struct RasInfo *Next; /* for dual-playfield */
struct BitMap *BitMap; /* the actual bitmap */
WORD RxOffset; /* horizontal scroll within bitmap */
WORD RyOffset; /* vertical scroll within bitmap */
};
```
---
## Display Mode Flags
```c
/* graphics/view.h */
#define HIRES 0x8000 /* 640 pixel mode */
#define LACE 0x0004 /* interlaced */
#define HAM 0x0800 /* Hold-And-Modify (4096 colours) */
#define EXTRA_HALFBRITE 0x0080 /* Extra Half-Brite (64 colours) */
#define DUALPF 0x0400 /* dual playfield */
#define PFBA 0x0040 /* playfield B has priority */
#define SUPERHIRES 0x0020 /* 1280 pixel mode (ECS+) */
#define VP_HIDE 0x2000 /* viewport is hidden */
```
---
## Building a Display
```c
struct View view;
struct ViewPort vp;
struct RasInfo ri;
struct BitMap *bm = AllocBitMap(320, 256, 5, BMF_DISPLAYABLE|BMF_CLEAR, NULL);
InitView(&view);
InitVPort(&vp);
view.ViewPort = &vp;
vp.RasInfo = &ri;
ri.BitMap = bm;
vp.DWidth = 320;
vp.DHeight = 256;
vp.Modes = 0; /* lores */
/* Build colour map: */
vp.ColorMap = GetColorMap(32);
/* Compile to copper: */
MakeVPort(&view, &vp);
MrgCop(&view);
/* Activate: */
LoadView(&view);
WaitTOF();
/* Cleanup: */
LoadView(GfxBase->ActiView); /* restore system view */
FreeVPortCopLists(&vp);
FreeCprList(view.LOFCprList);
FreeColorMap(vp.ColorMap);
FreeBitMap(bm);
```
---
## References
- NDK39: `graphics/view.h`
- ADCD 2.1: `InitView`, `InitVPort`, `MakeVPort`, `MrgCop`, `LoadView`
- HRM: display construction chapter