mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
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:
parent
f07a368bf1
commit
21751c0025
172 changed files with 19701 additions and 0 deletions
41
01_hardware/ocs_a500/README.md
Normal file
41
01_hardware/ocs_a500/README.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md)
|
||||
|
||||
# OCS Chipset — A500 / A1000 / A2000
|
||||
|
||||
## Overview
|
||||
|
||||
The **Original Chip Set** (OCS) ships in the Amiga 1000 (1985), A500 (1987), and early A2000 boards. It consists of three custom chips: **Agnus**, **Denise**, and **Paula**, supported by the MOS 8520 CIA pair.
|
||||
|
||||
## Chip Summary
|
||||
|
||||
| Chip | MOS Part | Primary Responsibilities |
|
||||
|---|---|---|
|
||||
| **Agnus** | 8361 (PAL), 8367 (NTSC) | DMA controller, Copper coprocessor, Blitter, address generation |
|
||||
| **Denise** | 8362 | Display: bitplane fetch decode, sprite decode, colour output |
|
||||
| **Paula** | 8364 | Audio DMA (4 channels), floppy disk I/O, serial port, interrupts |
|
||||
|
||||
## Contents
|
||||
|
||||
| File | Topic |
|
||||
|---|---|
|
||||
| [chipset_ocs.md](chipset_ocs.md) | Chip internals, DMA priorities, bus arbitration |
|
||||
| [custom_registers.md](custom_registers.md) | Full OCS register map $DFF000–$DFF1FE |
|
||||
| [copper.md](copper.md) | Copper coprocessor: WAIT/SKIP/MOVE, copperlist format |
|
||||
| [blitter.md](blitter.md) | Blitter: channels A/B/C/D, minterms, line mode, fill |
|
||||
| [paula_audio.md](paula_audio.md) | Audio DMA: AUDxLCH/LCL/LEN/PER/VOL, interrupt |
|
||||
| [paula_serial.md](paula_serial.md) | Serial port: SERPER/SERDATR, baud rate |
|
||||
| [sprites.md](sprites.md) | Hardware sprites: SPRxPTH, control words, attach mode |
|
||||
|
||||
## OCS Limitations vs ECS/AGA
|
||||
|
||||
- Max **512 KB Chip RAM** on A500 rev 5 and earlier (Agnus 8361/8367 addresses 512 KB only)
|
||||
- A500 rev 6+ allows 1 MB with Fat Agnus (part of later OCS run)
|
||||
- No productivity display modes (ECS adds BEAMCON0)
|
||||
- 32 colours max (or 64 EHB, or HAM 12-bit) in standard bitplane modes
|
||||
- Blitter is 16-bit; no 64-bit fetch (AGA adds FMODE)
|
||||
- No ECS Denise border features
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual: http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0000.html
|
||||
- *Amiga Hardware Reference Manual* 3rd ed., Chapter 5–8
|
||||
154
01_hardware/ocs_a500/blitter.md
Normal file
154
01_hardware/ocs_a500/blitter.md
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [OCS](README.md)
|
||||
|
||||
# Blitter
|
||||
|
||||
## Overview
|
||||
|
||||
The **Blitter** (Block Image Transferrer) is a DMA-driven coprocessor inside Agnus. It performs block copy, fill, and line-draw operations directly on Chip RAM without CPU involvement, at DMA bus speed.
|
||||
|
||||
## Channels
|
||||
|
||||
The Blitter has four channels:
|
||||
|
||||
| Channel | Role | Register Pointer |
|
||||
|---|---|---|
|
||||
| **A** | Source (with mask) | BLTAPTH/BLTAPTL |
|
||||
| **B** | Source (with shift) | BLTBPTH/BLTBPTL |
|
||||
| **C** | Source (destination content) | BLTCPTH/BLTCPTL |
|
||||
| **D** | Destination | BLTDPTH/BLTDPTL |
|
||||
|
||||
Any channel can be disabled per operation. The result written to D is computed as a **minterm** (boolean function) of A, B, C.
|
||||
|
||||
## BLTCON0 — Control Register 0
|
||||
|
||||
```
|
||||
bit 15-8: USEA, USEB, USEC, USED (enable channels A/B/C/D)
|
||||
bit 7-0: LF (Logic Function / minterm) — 8-bit truth table
|
||||
Bit = result bit for combination of A,B,C
|
||||
Bit 7: !A!B!C
|
||||
Bit 6: A!B!C
|
||||
Bit 5: !AB!C
|
||||
Bit 4: AB!C
|
||||
Bit 3: !A!BC
|
||||
Bit 2: A!BC
|
||||
Bit 1: !ABC
|
||||
Bit 0: ABC
|
||||
```
|
||||
|
||||
### Common Minterm Values
|
||||
|
||||
| Minterm | Hex | Operation |
|
||||
|---|---|---|
|
||||
| D = A AND B | $C0 | Mask copy |
|
||||
| D = A | $F0 | Simple copy (A only) |
|
||||
| D = A OR C | $FC | Overlay (A onto C) |
|
||||
| D = A XOR C | $3C | XOR blit |
|
||||
| D = NOT A | $0F | Invert A |
|
||||
| D = (A AND B) OR (!A AND C) | $CA | Cookie-cut (transparency) |
|
||||
|
||||
### Cookie-Cut Example
|
||||
|
||||
Cookie-cut (transparent sprite blit):
|
||||
```asm
|
||||
; A = mask (1=opaque, 0=transparent)
|
||||
; B = sprite data
|
||||
; C = background
|
||||
; D = result: background where mask=0, sprite where mask=1
|
||||
; Minterm: D = (A AND B) OR (!A AND C) = $CA
|
||||
|
||||
move.w #$09F0, BLTCON0 ; USE A,B,C,D; minterm=$CA
|
||||
move.w #$0000, BLTCON1
|
||||
```
|
||||
|
||||
## BLTCON1 — Control Register 1
|
||||
|
||||
```
|
||||
bit 15: DOFF — disable D write (dry run for fill detection)
|
||||
bit 4: IFE — inclusive fill enable
|
||||
bit 3: EFE — exclusive fill enable
|
||||
bit 2: FCI — fill carry in (start state)
|
||||
bit 1: DESC — descending mode (blit from bottom-right)
|
||||
bit 0: LINE — line draw mode
|
||||
```
|
||||
|
||||
## BLTSIZE — Start Blitter
|
||||
|
||||
```
|
||||
BLTSIZE = (height << 6) | width_in_words
|
||||
```
|
||||
|
||||
Writing to BLTSIZE starts the blit operation immediately. The blitter holds the bus until complete.
|
||||
|
||||
Example — blit 16×16 pixels (1 word wide, 16 lines):
|
||||
```asm
|
||||
move.w #((16<<6)|1), BLTSIZE
|
||||
```
|
||||
|
||||
Example — blit 320×256 (20 words wide, 256 lines):
|
||||
```asm
|
||||
move.w #((256<<6)|20), BLTSIZE
|
||||
```
|
||||
|
||||
## Modulo Registers
|
||||
|
||||
Modulo is the number of **bytes** to skip at the end of each row (to move to the start of the next row in a larger bitmap):
|
||||
|
||||
```
|
||||
BLTxMOD = (bytes_per_row_in_bitmap) - (width_of_blit_in_bytes)
|
||||
```
|
||||
|
||||
For a 320-pixel wide (40-byte row) bitmap, blitting a 32-pixel (4-byte) wide section:
|
||||
```
|
||||
Modulo = 40 - 4 = 36
|
||||
```
|
||||
|
||||
## First/Last Word Masks
|
||||
|
||||
`BLTAFWM` (first word mask) and `BLTALWM` (last word mask) mask the A channel for the first and last word of each blit row, allowing sub-word-aligned blitting.
|
||||
|
||||
For a fully aligned blit with no partial words:
|
||||
```asm
|
||||
move.w #$FFFF, BLTAFWM
|
||||
move.w #$FFFF, BLTALWM
|
||||
```
|
||||
|
||||
## Line Draw Mode (BLTCON1 bit 0)
|
||||
|
||||
In line mode, the blitter draws a line between two points using the Bresenham algorithm:
|
||||
- A channel provides the single pixel pattern (usually $8000 for MSB)
|
||||
- D channel is the destination bitmap
|
||||
- BLTSIZE specifies the line length (height=octant length, width=2)
|
||||
- BLTCON1 encodes octant, sign flags, and texture data
|
||||
|
||||
Line mode is used by `graphics.library` `Draw()` calls internally.
|
||||
|
||||
## Fill Mode (BLTCON1 IFE/EFE)
|
||||
|
||||
**Exclusive fill (EFE):** Each set bit toggles the fill state — produces XOR fill (like polygon rasterisation).
|
||||
**Inclusive fill (IFE):** Set bit turns fill on, stays on until end of row — used for solid polygon fill.
|
||||
|
||||
Fill operates in D channel only (no source channels active). BLTCON1 `DESC` bit = 1 when filling bottom-up.
|
||||
|
||||
## Waiting for Blitter Completion
|
||||
|
||||
```asm
|
||||
; Busy-wait on BLTCON0 busy bit
|
||||
WaitBlit:
|
||||
btst #6, DMACONR+1 ; test BBUSY bit (bit 14 of DMACONR, byte=bit6)
|
||||
bne.s WaitBlit
|
||||
```
|
||||
|
||||
Or via exec (preferred):
|
||||
```c
|
||||
WaitBlit(); /* graphics.library — waits and resets to safe state */
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Never start a blit while the blitter is busy. Always call `WaitBlit()` or poll `DMACONR[BBUSY]` before setting up new blit registers.
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — Blitter chapter
|
||||
- NDK39: `hardware/blit.h`, `graphics/blitattr.h`
|
||||
- graphics.library Autodocs: `BltBitMap`, `BltTemplate`, `BltClear`
|
||||
- http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node006D.html
|
||||
107
01_hardware/ocs_a500/chipset_ocs.md
Normal file
107
01_hardware/ocs_a500/chipset_ocs.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [OCS](README.md)
|
||||
|
||||
# OCS Chipset Internals
|
||||
|
||||
## Architecture
|
||||
|
||||
The three OCS chips share a common **chip bus** (also called the chip bus or DMA bus). Agnus is the bus master — it arbitrates between the CPU, Copper, Blitter, and DMA channels.
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 3
|
||||
CPU["68000 CPU"] Agnus["Agnus\n(DMA Master)"] ChipRAM["Chip RAM\n512 KB"]
|
||||
space Paula["Paula\n(Audio/Disk/Serial)"] space
|
||||
space Denise["Denise\n(Display)"] space
|
||||
CPU-- "bus request" -->Agnus
|
||||
Agnus-- "DMA cycles" -->ChipRAM
|
||||
Paula-- "DMA req" -->Agnus
|
||||
Denise-- "bitplane/sprite data" -->Agnus
|
||||
```
|
||||
|
||||
## DMA Channels and Priorities
|
||||
|
||||
Agnus schedules DMA cycles across a fixed priority scheme within each horizontal raster line (228 colour clocks per line, PAL):
|
||||
|
||||
| Priority | DMA Channel | Register Bits |
|
||||
|---|---|---|
|
||||
| 1 (highest) | Disk | `DMACONR[4]` DSKEN |
|
||||
| 2 | Sprite | `DMACONR[2]` SPREN |
|
||||
| 3 | Bitplane | `DMACONR[8]` BPLEN |
|
||||
| 4 | Copper | `DMACONR[7]` COPEN |
|
||||
| 5 | Blitter | `DMACONR[6]` BLTEN |
|
||||
| 6 | Audio ch 0–3 | `DMACONR[0..3]` AUD0–AUD3 |
|
||||
| 7 (lowest) | CPU | Remaining cycles |
|
||||
|
||||
The CPU only gets cycles not consumed by DMA — this is why heavy DMA usage (e.g., full-screen bitplanes + sprites + audio) can starve the CPU noticeably on OCS.
|
||||
|
||||
## DMACON Register
|
||||
|
||||
Write `$DFF096` (DMACON), read `$DFF002` (DMACONR):
|
||||
|
||||
```
|
||||
bit 15: SET/CLR — write: 1=set bits, 0=clear bits (read: always 0)
|
||||
bit 14: BBUSY — blitter busy (read only)
|
||||
bit 13: BZERO — blitter zero flag (read only)
|
||||
bit 10: (reserved)
|
||||
bit 9: MASTER — master DMA enable (must be set for any DMA)
|
||||
bit 8: BPLEN — bitplane DMA
|
||||
bit 7: COPEN — Copper DMA
|
||||
bit 6: BLTEN — Blitter DMA
|
||||
bit 5: SPREN — Sprite DMA
|
||||
bit 4: DSKEN — Disk DMA
|
||||
bit 3: AUD3EN — Audio channel 3 DMA
|
||||
bit 2: AUD2EN — Audio channel 2 DMA
|
||||
bit 1: AUD1EN — Audio channel 1 DMA
|
||||
bit 0: AUD0EN — Audio channel 0 DMA
|
||||
```
|
||||
|
||||
Enable all standard DMA:
|
||||
```asm
|
||||
move.w #$8380,DMACON ; SET + MASTER + BPLEN + COPEN
|
||||
move.w #$800F,DMACON ; SET + AUD0-3
|
||||
```
|
||||
|
||||
## INTENA / INTREQ — Interrupt System
|
||||
|
||||
Write `$DFF09A` (INTENA), read `$DFF01C` (INTENAR):
|
||||
Write `$DFF09C` (INTREQ), read `$DFF01E` (INTREQR):
|
||||
|
||||
```
|
||||
bit 14: INTEN — global interrupt enable (INTENA only)
|
||||
bit 13: EXTER — external/CIA interrupt (IPL6)
|
||||
bit 12: DSKSYNC — disk sync (IPL5)
|
||||
bit 11: RBF — serial receive buffer full (IPL5)
|
||||
bit 10: AUD3 — audio channel 3 (IPL4)
|
||||
bit 9: AUD2 — audio channel 2 (IPL4)
|
||||
bit 8: AUD1 — audio channel 1 (IPL4)
|
||||
bit 7: AUD0 — audio channel 0 (IPL4)
|
||||
bit 6: BLIT — blitter finished (IPL3)
|
||||
bit 5: VERTB — vertical blank (IPL3)
|
||||
bit 4: COPPER — copper interrupt (IPL3)
|
||||
bit 3: PORTS — CIA-A port interrupts (IPL2)
|
||||
bit 2: SOFT — software interrupt (IPL1)
|
||||
bit 1: DSKBLK — disk block finished (IPL1)
|
||||
bit 0: TBE — serial transmit buffer empty (IPL1)
|
||||
```
|
||||
|
||||
To enable vertical blank interrupt:
|
||||
```asm
|
||||
move.w #$C020,INTENA ; SET + INTEN + VERTB
|
||||
```
|
||||
|
||||
## Agnus: Bitplane DMA Timing
|
||||
|
||||
During each scan line, Agnus fetches bitplane data for the current line. For a 320-pixel wide, 4-bitplane display, Agnus takes 40 DMA cycles per line for bitplane fetch. On a standard PAL line with 227 clock cycles, this leaves ~187 cycles for CPU + other DMA.
|
||||
|
||||
**Bitplane DMA pointers** (set at start of each frame or via Copper):
|
||||
```
|
||||
BPL1PTH/BPL1PTL $DFF0E0/$DFF0E2 Bitplane 1 pointer (high/low word)
|
||||
BPL2PTH/BPL2PTL $DFF0E4/$DFF0E6
|
||||
... up to BPL6 for OCS (6 bitplanes max)
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — Agnus/DMA chapters
|
||||
- NDK39: `hardware/dmabits.h`, `hardware/intbits.h`, `hardware/custom.h`
|
||||
- *Amiga Hardware Reference Manual* 3rd ed.
|
||||
128
01_hardware/ocs_a500/copper.md
Normal file
128
01_hardware/ocs_a500/copper.md
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [OCS](README.md)
|
||||
|
||||
# Copper Coprocessor
|
||||
|
||||
## Overview
|
||||
|
||||
The **Copper** (co-processor) is built into Agnus. It executes a simple instruction list (the **copperlist**) in sync with the video beam, allowing precise per-scanline changes to any writable custom register — without CPU intervention.
|
||||
|
||||
The Copper can only write to custom registers (it cannot access Chip RAM directly), but it can change bitplane pointers, colours, BPLCON0, sprite pointers, and any other `$DFF0xx` register on a cycle-accurate basis.
|
||||
|
||||
## Copper Instruction Set
|
||||
|
||||
The Copper has exactly **three instructions**, each exactly **32 bits** (two 16-bit words):
|
||||
|
||||
### 1. MOVE — Write a Register
|
||||
|
||||
```
|
||||
Word 1: [RRR RRRR RRR0] Destination register address (must be even, bit 0 = 0)
|
||||
Word 2: [DDDD DDDD DDDD] Data to write
|
||||
```
|
||||
|
||||
Example — set COLOR00 to red at scanline 100:
|
||||
```
|
||||
DC.W $0180, $0F00 ; MOVE COLOR00, $0F00 (red)
|
||||
```
|
||||
|
||||
### 2. WAIT — Wait for Beam Position
|
||||
|
||||
```
|
||||
Word 1: [VVVV VVVH HHHH HH1] Vertical pos[8:1], Horizontal pos[8:3], bit0=1
|
||||
Word 2: [EVVV VVVH HHHH HHx0] Enable, VP mask, HP mask, bit0=0
|
||||
```
|
||||
|
||||
The Copper stalls until the beam reaches `(V,H) AND (Vmask,Hmask)`.
|
||||
|
||||
Standard full-precision WAIT:
|
||||
```
|
||||
DC.W $6401, $FF00 ; WAIT for line $64 (100), any H — full V mask
|
||||
```
|
||||
|
||||
WAIT for end of frame (copper stop):
|
||||
```
|
||||
DC.W $FFFF, $FFFE ; WAIT $FF,$FF — impossible position → stop copper
|
||||
```
|
||||
|
||||
### 3. SKIP — Conditional Skip
|
||||
|
||||
```
|
||||
Word 1: [VVVV VVVH HHHH HH1] Same format as WAIT
|
||||
Word 2: [EVVV VVVH HHHH HHx1] Same as WAIT but bit 0 = 1 (SKIP flag)
|
||||
```
|
||||
|
||||
If beam has passed the position, skip the next instruction. Used for double-buffered copper switching.
|
||||
|
||||
## Copperlist Format
|
||||
|
||||
A copperlist is an array of 32-bit instruction pairs in **Chip RAM**, terminated by:
|
||||
```
|
||||
DC.W $FFFF, $FFFE
|
||||
```
|
||||
|
||||
Example — colour cycle on vertical blank:
|
||||
```asm
|
||||
Copperlist:
|
||||
DC.W $0180, $0000 ; COLOR00 = black
|
||||
DC.W $4401, $FF00 ; WAIT line 68 (display area start)
|
||||
DC.W $0180, $0F00 ; COLOR00 = red
|
||||
DC.W $6401, $FF00 ; WAIT line 100
|
||||
DC.W $0180, $00F0 ; COLOR00 = green
|
||||
DC.W $FFFF, $FFFE ; END
|
||||
```
|
||||
|
||||
## Copper Pointers and Control
|
||||
|
||||
| Register | Offset | Description |
|
||||
|---|---|---|
|
||||
| COP1LCH | $080 | Copper list 1 pointer high word |
|
||||
| COP1LCL | $082 | Copper list 1 pointer low word |
|
||||
| COP2LCH | $084 | Copper list 2 pointer high word |
|
||||
| COP2LCL | $086 | Copper list 2 pointer low word |
|
||||
| COPJMP1 | $088 | Strobe: restart copper from list 1 (any write) |
|
||||
| COPJMP2 | $08A | Strobe: restart copper from list 2 |
|
||||
| COPCON | $02E | Copper danger bit (CDANG) |
|
||||
|
||||
**COPCON** bit 1 (`CDANG`): When set, Copper is allowed to write to registers `$40`–`$7F` (blitter registers). Should be 0 in normal use to prevent runaway copperlists from corrupting the blitter.
|
||||
|
||||
## Activating the Copper
|
||||
|
||||
```asm
|
||||
; Load copperlist address into copper list 1
|
||||
move.l #Copperlist, d0
|
||||
move.w d0, COP1LCL+custom ; low word
|
||||
swap d0
|
||||
move.w d0, COP1LCH+custom ; high word
|
||||
|
||||
; Restart copper (triggers on next VBlank)
|
||||
move.w d0, COPJMP1+custom ; value irrelevant, strobe only
|
||||
|
||||
; Enable copper DMA
|
||||
move.w #$8280, DMACON+custom ; SET + MASTER + COPEN
|
||||
```
|
||||
|
||||
## Dual-Playfield and HAM via Copper
|
||||
|
||||
Common copper techniques:
|
||||
|
||||
**Split-screen different palettes:** Change `COLOR00`–`COLOR31` registers mid-screen via a WAIT at the split scanline.
|
||||
|
||||
**Mid-screen bitplane pointer change:** Redirect `BPL1PTH/BPL1PTL` to a different bitmap half-way through the display — used for large vertical scrolling without double-buffering the full screen.
|
||||
|
||||
**BPLCON0 mid-screen:** Switch between `HIRES` and `LORES`, or between 6-plane and 4-plane modes, on different lines.
|
||||
|
||||
**Raster bars:** Write a different colour to COLOR00 on every scanline using sequential WAIT+MOVE pairs.
|
||||
|
||||
## Graphics Library vs Direct Copper
|
||||
|
||||
AmigaOS's `graphics.library` manages the Copper list internally:
|
||||
- `MrgCop()` merges system and user copper lists
|
||||
- `LoadView()` installs a View structure's copper list
|
||||
- `WaitTOF()` waits for the top-of-frame (VBlank) before the copper restarts
|
||||
|
||||
Direct copper access should be done via `GetColorMap()`, `SetRGB4()` and official graphics calls, or through a custom `View`/`ViewPort`/`ColorMap` structure passed to `LoadView()`.
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — Copper chapter
|
||||
- NDK39: `hardware/custom.h`, `graphics/copper.h`
|
||||
- *Amiga Hardware Reference Manual* 3rd ed., Chapter 6
|
||||
183
01_hardware/ocs_a500/custom_registers.md
Normal file
183
01_hardware/ocs_a500/custom_registers.md
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [OCS](README.md)
|
||||
|
||||
# OCS Custom Register Map
|
||||
|
||||
Base address: `$00DFF000`. All registers are 16-bit (word) wide. Byte access is valid for the appropriate byte lane.
|
||||
|
||||
Legend: **R** = read, **W** = write, **RW** = read-write, **S** = strobe (write triggers action)
|
||||
|
||||
## DMA and Interrupt Control
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $002 | DMACONR | R | DMA control register (read) |
|
||||
| $01C | INTENAR | R | Interrupt enable (read) |
|
||||
| $01E | INTREQR | R | Interrupt request (read) |
|
||||
| $096 | DMACON | W | DMA control (write: bit15=SET/CLR) |
|
||||
| $09A | INTENA | W | Interrupt enable (write: bit15=SET/CLR) |
|
||||
| $09C | INTREQ | W | Interrupt request — ack / force |
|
||||
|
||||
## Beam Position (Read Only)
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $004 | VPOSR | R | Vertical position high, LOF bit |
|
||||
| $006 | VHPOSR | R | Vertical + horizontal beam position |
|
||||
| $007 | VHPOS | R | Horizontal beam position (byte) |
|
||||
|
||||
## Copper
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $02E | COPCON | W | Copper control (CDANG bit) |
|
||||
| $080 | COP1LCH | W | Copper list 1 pointer high |
|
||||
| $082 | COP1LCL | W | Copper list 1 pointer low |
|
||||
| $084 | COP2LCH | W | Copper list 2 pointer high |
|
||||
| $086 | COP2LCL | W | Copper list 2 pointer low |
|
||||
| $088 | COPJMP1 | S | Restart Copper from list 1 |
|
||||
| $08A | COPJMP2 | S | Restart Copper from list 2 |
|
||||
| $08C | COPINS | W | Copper instruction (direct write) |
|
||||
| $000 | BLTDDAT | R | Blitter dest early read (Copper use) |
|
||||
|
||||
## Blitter
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $040 | BLTCON0 | W | Blitter control 0 (minterm, channels) |
|
||||
| $042 | BLTCON1 | W | Blitter control 1 (line mode, fill) |
|
||||
| $044 | BLTAFWM | W | First word mask, channel A |
|
||||
| $046 | BLTALWM | W | Last word mask, channel A |
|
||||
| $048 | BLTCPTH | W | Channel C pointer high |
|
||||
| $04A | BLTCPTL | W | Channel C pointer low |
|
||||
| $04C | BLTBPTH | W | Channel B pointer high |
|
||||
| $04E | BLTBPTL | W | Channel B pointer low |
|
||||
| $050 | BLTAPTH | W | Channel A pointer high |
|
||||
| $052 | BLTAPTL | W | Channel A pointer low |
|
||||
| $054 | BLTDPTH | W | Destination pointer high |
|
||||
| $056 | BLTDPTL | W | Destination pointer low |
|
||||
| $058 | BLTSIZE | W | Blitter size + start (height×64 + width) |
|
||||
| $060 | BLTCMOD | W | Channel C modulo |
|
||||
| $062 | BLTBMOD | W | Channel B modulo |
|
||||
| $064 | BLTAMOD | W | Channel A modulo |
|
||||
| $066 | BLTDMOD | W | Destination modulo |
|
||||
| $070 | BLTCDAT | W | Channel C data register |
|
||||
| $072 | BLTBDAT | W | Channel B data register |
|
||||
| $074 | BLTADAT | W | Channel A data register |
|
||||
|
||||
## Bitplane Pointers
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $0E0 | BPL1PTH | W | Bitplane 1 pointer high |
|
||||
| $0E2 | BPL1PTL | W | Bitplane 1 pointer low |
|
||||
| $0E4 | BPL2PTH | W | Bitplane 2 pointer high |
|
||||
| $0E6 | BPL2PTL | W | Bitplane 2 pointer low |
|
||||
| $0E8 | BPL3PTH | W | Bitplane 3 pointer high |
|
||||
| $0EA | BPL3PTL | W | Bitplane 3 pointer low |
|
||||
| $0EC | BPL4PTH | W | Bitplane 4 pointer high |
|
||||
| $0EE | BPL4PTL | W | Bitplane 4 pointer low |
|
||||
| $0F0 | BPL5PTH | W | Bitplane 5 pointer high |
|
||||
| $0F2 | BPL5PTL | W | Bitplane 5 pointer low |
|
||||
| $0F4 | BPL6PTH | W | Bitplane 6 pointer high |
|
||||
| $0F6 | BPL6PTL | W | Bitplane 6 pointer low |
|
||||
|
||||
## Bitplane Control
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $100 | BPLCON0 | W | Bitplane control 0 (depth, HAM, HIRES, LACE) |
|
||||
| $102 | BPLCON1 | W | Bitplane scroll (fine scroll values) |
|
||||
| $104 | BPLCON2 | W | Sprite vs bitplane priority |
|
||||
| $108 | BPL1MOD | W | Bitplane modulo (odd planes) |
|
||||
| $10A | BPL2MOD | W | Bitplane modulo (even planes) |
|
||||
| $110 | BPL1DAT | W | Bitplane 1 data register |
|
||||
| $112 | BPL2DAT | W | Bitplane 2 data register |
|
||||
| $114 | BPL3DAT | W | Bitplane 3 |
|
||||
| $116 | BPL4DAT | W | Bitplane 4 |
|
||||
| $118 | BPL5DAT | W | Bitplane 5 |
|
||||
| $11A | BPL6DAT | W | Bitplane 6 |
|
||||
|
||||
**BPLCON0 bit layout:**
|
||||
```
|
||||
bit 15: HIRES (1 = 640 pixel wide)
|
||||
bit 14-12: BPU2-0 (number of bitplanes: 0–6)
|
||||
bit 11: HAM (1 = Hold-And-Modify mode)
|
||||
bit 10: DPF (dual playfield)
|
||||
bit 9: COLOR (0 = monochrome, 1 = colour)
|
||||
bit 8: GAUD (genlock audio)
|
||||
bit 7-4: (various, OCS = 0)
|
||||
bit 1: ERSY (external sync)
|
||||
bit 0: ECSENA (ECS enable — must be 0 on OCS)
|
||||
```
|
||||
|
||||
## Display Window and Fetch
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $08E | DIWSTRT | W | Display window start (V and H start) |
|
||||
| $090 | DIWSTOP | W | Display window stop |
|
||||
| $092 | DDFSTRT | W | Display data fetch start |
|
||||
| $094 | DDFSTOP | W | Display data fetch stop |
|
||||
|
||||
## Sprite Pointers and Data
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $120 | SPR0PTH | W | Sprite 0 pointer high |
|
||||
| $122 | SPR0PTL | W | Sprite 0 pointer low |
|
||||
| ... | ... | | Sprites 1–7 follow at +4 each |
|
||||
| $13E | SPR7PTL | W | Sprite 7 pointer low |
|
||||
| $140 | SPR0POS | W | Sprite 0 position |
|
||||
| $142 | SPR0CTL | W | Sprite 0 control |
|
||||
| $144 | SPR0DATA | W | Sprite 0 image data word A |
|
||||
| $146 | SPR0DATB | W | Sprite 0 image data word B |
|
||||
| ... | | | Sprites 1–7 follow |
|
||||
| $178 | SPR7DATB | W | Sprite 7 image data word B |
|
||||
|
||||
## Audio Registers
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $0A0 | AUD0LCH | W | Audio ch 0 pointer high |
|
||||
| $0A2 | AUD0LCL | W | Audio ch 0 pointer low |
|
||||
| $0A4 | AUD0LEN | W | Audio ch 0 length (words) |
|
||||
| $0A6 | AUD0PER | W | Audio ch 0 period (clock divider) |
|
||||
| $0A8 | AUD0VOL | W | Audio ch 0 volume (0–64) |
|
||||
| $0AA | AUD0DAT | W | Audio ch 0 data (direct, non-DMA) |
|
||||
| ... | | | Channels 1–3 follow at +$10 |
|
||||
|
||||
## Serial Port
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $030 | SERDAT | W | Serial data and stop bits |
|
||||
| $018 | SERDATR | R | Serial data receive and status |
|
||||
| $032 | SERPER | W | Serial period and word length |
|
||||
|
||||
## Disk DMA
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $020 | DSKPTH | W | Disk pointer high |
|
||||
| $022 | DSKPTL | W | Disk pointer low |
|
||||
| $024 | DSKLEN | W | Disk length and write flag |
|
||||
| $010 | ADKCONR | R | Audio / disk control (read) |
|
||||
| $09E | ADKCON | W | Audio / disk control (write) |
|
||||
| $07C | DSKSYNC | W | Disk sync word |
|
||||
|
||||
## Colour Registers
|
||||
|
||||
| Offset | Name | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| $180 | COLOR00 | W | Background / colour 0 |
|
||||
| $182 | COLOR01 | W | Colour 1 |
|
||||
| ... | | | |
|
||||
| $1BE | COLOR31 | W | Colour 31 |
|
||||
|
||||
OCS colours: 12-bit RGB (4 bits per component, $0RGB format).
|
||||
|
||||
## References
|
||||
|
||||
- *Amiga Hardware Reference Manual* 3rd ed. — Appendix B: Register Summary
|
||||
- NDK39: `hardware/custom.h` — struct Custom definition
|
||||
- http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0000.html
|
||||
135
01_hardware/ocs_a500/paula_audio.md
Normal file
135
01_hardware/ocs_a500/paula_audio.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [OCS](README.md)
|
||||
|
||||
# Paula — Audio DMA
|
||||
|
||||
## Overview
|
||||
|
||||
**Paula** (MOS 8364) provides four independent audio DMA channels (0–3), corresponding to the four hardware voice outputs:
|
||||
|
||||
| Channel | Stereo Output |
|
||||
|---|---|
|
||||
| 0 | Left |
|
||||
| 1 | Right |
|
||||
| 2 | Right |
|
||||
| 3 | Left |
|
||||
|
||||
Each channel has its own DMA pointer, length, period (pitch), and volume registers. Paula fetches sample data from **Chip RAM** automatically at the rate set by the period register.
|
||||
|
||||
## Audio Registers Per Channel
|
||||
|
||||
Channel `n` (n = 0–3) registers at `$DFF0A0 + n×$10`:
|
||||
|
||||
| Offset | Name | Description |
|
||||
|---|---|---|
|
||||
| +$00/$01 | AUDnLCH/AUDnLCL | Sample pointer high/low (Chip RAM address) |
|
||||
| +$04 | AUDnLEN | Sample length in words (not bytes) |
|
||||
| +$06 | AUDnPER | Period — clock divider for playback rate |
|
||||
| +$08 | AUDnVOL | Volume: 0–64 (0 = silent, 64 = full) |
|
||||
| +$0A | AUDnDAT | Current sample word (direct, for non-DMA mode) |
|
||||
|
||||
## Sample Playback Rate
|
||||
|
||||
Paula derives playback rate from the system clock divided by the period register:
|
||||
|
||||
```
|
||||
Sample rate (Hz) = System clock / Period
|
||||
```
|
||||
|
||||
| System | Clock | Period for 8363 Hz | Period for 22050 Hz |
|
||||
|---|---|---|---|
|
||||
| PAL | 3,546,895 Hz | 428 | ~161 |
|
||||
| NTSC | 3,579,545 Hz | 428 | ~162 |
|
||||
|
||||
> **8363 Hz** is the standard MOD tracker reference — period 428 on PAL plays middle-A at exactly 8363 Hz.
|
||||
|
||||
Period range: 124–65535 (minimum period = maximum frequency ≈ 28 kHz PAL).
|
||||
|
||||
## Starting Audio DMA
|
||||
|
||||
```asm
|
||||
; Load channel 0 with sample at SampleData, length 256 words
|
||||
move.l #SampleData, d0
|
||||
move.w d0, AUD0LCL+custom
|
||||
swap d0
|
||||
move.w d0, AUD0LCH+custom
|
||||
move.w #256, AUD0LEN+custom ; 256 words = 512 bytes
|
||||
move.w #428, AUD0PER+custom ; period 428 = 8287 Hz PAL
|
||||
move.w #64, AUD0VOL+custom ; full volume
|
||||
|
||||
; Enable audio DMA for channel 0
|
||||
move.w #$8201, DMACON+custom ; SET + MASTER + AUD0EN
|
||||
|
||||
; Enable audio interrupt (optional)
|
||||
move.w #$A080, INTENA+custom ; SET + INTEN + AUD0
|
||||
```
|
||||
|
||||
## ADKCON — Audio/Disk Control
|
||||
|
||||
| Bit | Name | Description |
|
||||
|---|---|---|
|
||||
| 15 | SET/CLR | Write: 1=set, 0=clear bits |
|
||||
| 11 | PRECOMP1 | Disk precompensation |
|
||||
| 10 | PRECOMP0 | Disk precompensation |
|
||||
| 9 | MFMPREC | MFM precompensation |
|
||||
| 7 | MSBSYNC | Audio sync from MSB |
|
||||
| 6 | WORDSYNC | Disk word sync enable |
|
||||
| 4 | ATPER | Channel 3 period from channel 2 data |
|
||||
| 3 | ATVOL | Channel 3 volume from channel 2 data |
|
||||
| 2 | ATPER2 | Channel 1 period from channel 0 data |
|
||||
| 1 | ATVOL2 | Channel 1 volume from channel 0 data |
|
||||
| 0 | (unused) | |
|
||||
|
||||
`ATPER`/`ATVOL` bits enable **audio modulation** — channel N's period/volume is modulated by the sample data of channel N-1. Used for AM synthesis effects (e.g., in many MOD players for 8-channel soft mixing).
|
||||
|
||||
## Interrupt Handling
|
||||
|
||||
Audio channels raise interrupts when their DMA pointer wraps to the beginning of the next buffer:
|
||||
|
||||
```
|
||||
INTENA/INTREQ bits:
|
||||
AUD0 = bit 7 (IPL 4)
|
||||
AUD1 = bit 8 (IPL 4)
|
||||
AUD2 = bit 9 (IPL 4)
|
||||
AUD3 = bit 10 (IPL 4)
|
||||
```
|
||||
|
||||
The interrupt fires when the channel has consumed its buffer and reloaded the pointer from the DMA registers. At this point, software can update AUDnLCH/L and AUDnLEN with the next buffer.
|
||||
|
||||
## Double-Buffering Pattern
|
||||
|
||||
```c
|
||||
/* In interrupt handler (IPL 4 server for AUD0): */
|
||||
void audio_interrupt(void)
|
||||
{
|
||||
/* Swap buffers */
|
||||
UWORD *next = (active_buf == buf_a) ? buf_b : buf_a;
|
||||
active_buf = next;
|
||||
|
||||
/* Load next buffer address */
|
||||
custom.aud[0].ac_ptr = (UWORD *)next;
|
||||
custom.aud[0].ac_len = BUF_WORDS;
|
||||
}
|
||||
```
|
||||
|
||||
## Direct (Non-DMA) Audio
|
||||
|
||||
For simple sound effects without DMA overhead, write directly to `AUDnDAT`:
|
||||
```asm
|
||||
move.w #$0080, AUD0VOL+custom ; volume 64 (approx)
|
||||
move.w #$7FFF, AUD0DAT+custom ; max positive sample
|
||||
```
|
||||
This only produces a single sample word — not practical for continuous audio but useful for one-shot clicks/beeps.
|
||||
|
||||
## audio.device
|
||||
|
||||
AmigaOS provides `audio.device` for arbitrated, multi-application audio access:
|
||||
- Allocates channels (bitmask: `{1,2,4,8}`)
|
||||
- Creates `IOAudio` request, uses standard device I/O (`BeginIO`/`WaitIO`)
|
||||
- Handles period, volume, sample pointer, cycle count
|
||||
- See [10_devices/audio_device.md](../../10_devices/audio_device.md) for full API reference
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — Paula audio chapter
|
||||
- NDK39: `hardware/custom.h` (struct AudChannel), `devices/audio.h`
|
||||
- Autodocs: audio.device — http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node0081.html
|
||||
123
01_hardware/ocs_a500/paula_serial.md
Normal file
123
01_hardware/ocs_a500/paula_serial.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [OCS](README.md)
|
||||
|
||||
# Paula — Serial Port
|
||||
|
||||
## Overview
|
||||
|
||||
**Paula** contains a hardware UART (Universal Asynchronous Receiver/Transmitter) for the Amiga's serial port. It is a simple, non-buffered serial interface — no FIFO, single transmit and single receive register.
|
||||
|
||||
The serial port operates at **RS-232 voltage levels** (via external level shifter on the A500/A1000). The A2000 and A3000 route through a MAX232 equivalent.
|
||||
|
||||
## Registers
|
||||
|
||||
| Register | Offset | Dir | Description |
|
||||
|---|---|---|---|
|
||||
| SERPER | $DFF032 | W | Serial period and word length |
|
||||
| SERDAT | $DFF030 | W | Serial data transmit |
|
||||
| SERDATR | $DFF018 | R | Serial data receive + status |
|
||||
|
||||
## SERPER — Baud Rate Configuration
|
||||
|
||||
```
|
||||
bit 15: LONG — 0 = 8-bit words, 1 = 9-bit words
|
||||
bit 14-0: Period — clock divider for baud rate
|
||||
```
|
||||
|
||||
**Baud rate formula:**
|
||||
```
|
||||
Baud = System clock / (Period + 1)
|
||||
```
|
||||
|
||||
| Baud Rate | PAL Period | NTSC Period |
|
||||
|---|---|---|
|
||||
| 300 | 11811 | 11929 |
|
||||
| 1200 | 2952 | 2981 |
|
||||
| 2400 | 1476 | 1490 |
|
||||
| 4800 | 737 | 745 |
|
||||
| 9600 | 368 | 372 |
|
||||
| 19200 | 183 | 186 |
|
||||
| 38400 | 91 | 92 |
|
||||
| 115200 | 30 | 30 |
|
||||
|
||||
## SERDAT — Transmit
|
||||
|
||||
```
|
||||
bit 15-11: Must be 1 (stop bits framing)
|
||||
bit 10: Stop bit
|
||||
bit 9-0: Data word (8 or 9 bits, MSB first relative to wire)
|
||||
```
|
||||
|
||||
To transmit a byte (8-bit mode):
|
||||
```asm
|
||||
; Wait for TBE (transmit buffer empty) interrupt or poll
|
||||
WaitTBE:
|
||||
btst #0, SERDATR+1 ; TBE = bit 0 of SERDATR high byte...
|
||||
; Actually check INTREQR bit TBE
|
||||
beq.s WaitTBE
|
||||
|
||||
; Send byte $41 ('A'), 8-bit framing: $3C01 prefix + data
|
||||
move.w #($3FC0 | 0x41), SERDAT+custom
|
||||
```
|
||||
|
||||
Correct framing for 8-bit word:
|
||||
```
|
||||
SERDAT = $3C00 | byte_value ; bits[15:10] = %111111 (stop + start framing)
|
||||
```
|
||||
|
||||
## SERDATR — Receive
|
||||
|
||||
```
|
||||
bit 15: OVRUN — overrun error (data was not read before next byte arrived)
|
||||
bit 14: RBF — receive buffer full (data ready to read)
|
||||
bit 13: TBE — transmit buffer empty
|
||||
bit 12: TSRE — transmit shift register empty
|
||||
bit 11: RXD — current state of RXD pin
|
||||
bit 9: STP — stop bit of received word
|
||||
bit 8-0: Data — received byte (8 or 9 bits)
|
||||
```
|
||||
|
||||
Read a byte:
|
||||
```c
|
||||
/* Wait for RBF */
|
||||
while (!(custom.serdatr & SERDATF_RBF))
|
||||
;
|
||||
UBYTE ch = custom.serdatr & 0xFF;
|
||||
|
||||
/* Acknowledge interrupt */
|
||||
custom.intreq = INTF_RBF;
|
||||
```
|
||||
|
||||
## Interrupt Sources
|
||||
|
||||
| Event | INTENA/INTREQ bit | IPL |
|
||||
|---|---|---|
|
||||
| TBE (transmit buffer empty) | bit 0 `INTF_TBE` | 1 |
|
||||
| RBF (receive buffer full) | bit 11 `INTF_RBF` | 5 |
|
||||
|
||||
RBF fires at IPL 5 — relatively high priority, since the receive register has no FIFO and an overrun loses data.
|
||||
|
||||
## serial.device
|
||||
|
||||
AmigaOS provides `serial.device` for managed serial access:
|
||||
- Supports baud rates, parity, stop bits, word length
|
||||
- Provides buffered read/write via `IOExtSer` structure
|
||||
- Handles `CMD_READ`, `CMD_WRITE`, `SDCMD_SETPARAMS`, `SDCMD_QUERY`
|
||||
- Multiple opens are not supported — one opener at a time
|
||||
|
||||
```c
|
||||
#include <devices/serial.h>
|
||||
|
||||
struct IOExtSer *ser_req; /* allocated IOExtSer */
|
||||
OpenDevice("serial.device", 0, (struct IORequest *)ser_req, 0);
|
||||
|
||||
ser_req->io_Baud = 9600;
|
||||
ser_req->io_RBufLen = 4096;
|
||||
ser_req->IOSer.io_Command = SDCMD_SETPARAMS;
|
||||
DoIO((struct IORequest *)ser_req);
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — Paula serial section
|
||||
- NDK39: `hardware/custom.h`, `devices/serial.h`
|
||||
- Autodocs: serial.device — http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node013E.html
|
||||
136
01_hardware/ocs_a500/sprites.md
Normal file
136
01_hardware/ocs_a500/sprites.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [OCS](README.md)
|
||||
|
||||
# Hardware Sprites
|
||||
|
||||
## Overview
|
||||
|
||||
The OCS/ECS chipset provides **8 hardware sprites**, each 16 pixels wide and arbitrarily tall. They are managed by Agnus's DMA and rendered by Denise independently of the bitplane display. Sprites are commonly used for the mouse pointer, weapons, overlays, and animated objects that must not disturb the background.
|
||||
|
||||
## Sprite Properties (OCS)
|
||||
|
||||
| Property | OCS Value |
|
||||
|---|---|
|
||||
| Count | 8 sprites |
|
||||
| Width | 16 pixels fixed |
|
||||
| Height | Programmable (any number of lines) |
|
||||
| Colours | 3 (+1 transparent) per sprite |
|
||||
| Colour source | Sprite colour registers (COLOR16–COLOR31) |
|
||||
| Attach mode | Pairs 0/1, 2/3, 4/5, 6/7 → 15 colours |
|
||||
|
||||
## Sprite Registers
|
||||
|
||||
Each sprite `n` (0–7) has four registers at `$DFF120 + n×$08`:
|
||||
|
||||
| Offset | Name | Description |
|
||||
|---|---|---|
|
||||
| +$00/$01 | SPRnPTH/SPRnPTL | Sprite DMA pointer (high/low) |
|
||||
| +$04 | SPRnPOS | Vertical start, horizontal position |
|
||||
| +$06 | SPRnCTL | Vertical stop, attach flag, H LSB |
|
||||
| +$08 | SPRnDATA | Image data word A (current line) |
|
||||
| +$0A | SPRnDATB | Image data word B (current line) |
|
||||
|
||||
## SPRnPOS — Position Register
|
||||
|
||||
```
|
||||
bit 15-8: VSTART[8:1] Vertical start position (high 8 bits)
|
||||
bit 7-0: HSTART[8:1] Horizontal position (bits 8..1, shifted right)
|
||||
```
|
||||
|
||||
## SPRnCTL — Control Register
|
||||
|
||||
```
|
||||
bit 15-8: VSTOP[8:1] Vertical stop position
|
||||
bit 7: ATT Attach (pair this sprite with next)
|
||||
bit 2: HSTART[0] Horizontal position LSB
|
||||
bit 1: VSTOP[0] Vertical stop LSB
|
||||
bit 0: VSTART[0] Vertical start LSB
|
||||
```
|
||||
|
||||
## Horizontal Position Formula
|
||||
|
||||
```
|
||||
H pixel = (HSTART[8:0]) - 1
|
||||
```
|
||||
|
||||
Standard screen left edge is approximately H=128 (HSTART=$80).
|
||||
|
||||
## Sprite DMA Data Format
|
||||
|
||||
Each line of the sprite consists of two 16-bit words (DATA and DATB) fetched from Chip RAM:
|
||||
|
||||
```
|
||||
For each scanline of sprite:
|
||||
Word 1 (DATA): bit 15..0 → pixel bit 1 (colour bit 1)
|
||||
Word 2 (DATB): bit 15..0 → pixel bit 0 (colour bit 0)
|
||||
|
||||
Pixel colour:
|
||||
DATA[bit] = 0, DATB[bit] = 0 → transparent
|
||||
DATA[bit] = 0, DATB[bit] = 1 → colour 1 (COLOR17 for sprite 0)
|
||||
DATA[bit] = 1, DATB[bit] = 0 → colour 2 (COLOR18)
|
||||
DATA[bit] = 1, DATB[bit] = 1 → colour 3 (COLOR19)
|
||||
```
|
||||
|
||||
## Sprite Data in Memory
|
||||
|
||||
Agnus DMA reads the sprite from a memory block structured as:
|
||||
|
||||
```
|
||||
Word: SPRnPOS value (copied to register at DMA start)
|
||||
Word: SPRnCTL value (copied to register at DMA start)
|
||||
[Repeat for each line:]
|
||||
Word: SPRnDATA (image word A)
|
||||
Word: SPRnDATB (image word B)
|
||||
[End of sprite:]
|
||||
Word: $0000 (SPRnPOS = 0 → null position signals end)
|
||||
Word: $0000 (SPRnCTL = 0)
|
||||
```
|
||||
|
||||
## Colour Mapping
|
||||
|
||||
Sprites share colour registers with bitplanes:
|
||||
|
||||
| Sprites | Colour Registers |
|
||||
|---|---|
|
||||
| 0 and 1 | COLOR16–COLOR19 |
|
||||
| 2 and 3 | COLOR20–COLOR23 |
|
||||
| 4 and 5 | COLOR24–COLOR27 |
|
||||
| 6 and 7 | COLOR28–COLOR31 |
|
||||
|
||||
COLOR16 (the first colour of sprite pair 0/1) is always transparent — the sprite background. Only COLOR17–COLOR19 are visible for sprites 0/1.
|
||||
|
||||
## Attached Sprites (15 Colours)
|
||||
|
||||
Pairing two sprites (`ATT` bit in SPRnCTL of the even sprite) combines their DATA/DATB bits to produce a 4-bit colour index (16 colours, one transparent):
|
||||
|
||||
```
|
||||
4-bit colour = {SPR_even.DATA[bit], SPR_even.DATB[bit],
|
||||
SPR_odd.DATA[bit], SPR_odd.DATB[bit]}
|
||||
```
|
||||
|
||||
This gives 15 visible colours per pair, using COLOR16–COLOR31 for pair 0/1.
|
||||
|
||||
## BPLCON2 — Sprite Priority
|
||||
|
||||
`BPLCON2` ($DFF104) controls the display priority of sprites vs bitplanes:
|
||||
|
||||
```
|
||||
bit 5-3: PF2PRI, PF2P2-0 — Playfield 2 priority
|
||||
bit 2-0: PF1PRI, PF1P2-0 — Playfield 1 and sprite priority
|
||||
```
|
||||
|
||||
Default: sprites appear in front of all bitplanes.
|
||||
|
||||
## OS Mouse Pointer
|
||||
|
||||
AmigaOS's Intuition uses sprite 0 (and 1 in attached mode for colour pointer) for the mouse pointer. Intuition calls `SetPointer()` / `ClearPointer()` on a Window to install custom pointer sprites.
|
||||
|
||||
```c
|
||||
SetPointer(window, pointer_data, height, width, x_offset, y_offset);
|
||||
ClearPointer(window); /* restore system default */
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — Sprites chapter
|
||||
- NDK39: `hardware/sprite.h`, `intuition/intuition.h` (SetPointer)
|
||||
- http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node00D7.html
|
||||
Loading…
Add table
Add a link
Reference in a new issue