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
57
01_hardware/README.md
Normal file
57
01_hardware/README.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
[← Home](../README.md)
|
||||
|
||||
# Hardware — Chipset Generation Overview
|
||||
|
||||
## Generation Comparison
|
||||
|
||||
| Feature | OCS | ECS | AGA |
|
||||
|---|---|---|---|
|
||||
| Agnus | 8361/8367 | 8372A (Super Agnus) | Alice (8374) |
|
||||
| Denise | 8362 | 8373 (ECS Denise) | Lisa |
|
||||
| Paula | 8364 | 8364 (unchanged) | 8364 (unchanged) |
|
||||
| Max Chip RAM | 512 KB–1 MB | 1–2 MB | 2 MB |
|
||||
| Colours (max normal) | 32 | 32 | 256 |
|
||||
| HAM | 12-bit HAM (6bpp) | 12-bit HAM | 24-bit HAM8 (8bpp) |
|
||||
| Sprites | 8 × 16px | 8 × 16px | 8 × 64px, 256 colours |
|
||||
| Blitter bus | 16-bit | 16-bit | 64-bit (FMODE) |
|
||||
| Display modes | NTSC/PAL | +Productivity, VGA | +Doublescan, 31kHz |
|
||||
| Machines | A500/A1000/A2000 | A600/A3000/A500+ | A1200/A4000/CD32 |
|
||||
|
||||
---
|
||||
|
||||
## Custom Register Address Space
|
||||
|
||||
All chipset generations share the base address **$00DFF000** for custom registers. Registers are memory-mapped, mostly 16-bit wide.
|
||||
|
||||
```
|
||||
$DFF000 BLTDDAT Blitter destination early read
|
||||
$DFF002 DMACONR DMA control (read)
|
||||
$DFF004 VPOSR Vertical position (read, high)
|
||||
...
|
||||
$DFF180 COLOR00 Colour register 0
|
||||
...
|
||||
$DFF1FE (last OCS/ECS register)
|
||||
$DFF1FC BEAMCON0 (ECS+) beam control
|
||||
$DFF1FC+ (AGA extensions)
|
||||
```
|
||||
|
||||
See [custom_registers_full.md](../references/custom_registers_full.md) for the complete table across all chipsets.
|
||||
|
||||
---
|
||||
|
||||
## Navigation
|
||||
|
||||
| Subfolder | Content |
|
||||
|---|---|
|
||||
| [common/](common/) | M68k CPU, address space layout, CIA chips, Zorro bus |
|
||||
| [ocs_a500/](ocs_a500/) | OCS chipset — A500, A1000, A2000 |
|
||||
| [ecs_a600_a3000/](ecs_a600_a3000/) | ECS chipset — A600, A3000, A500+ |
|
||||
| [aga_a1200_a4000/](aga_a1200_a4000/) | AGA chipset — A1200, A4000, CD32 |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- *Amiga Hardware Reference Manual* 3rd ed. — `Hardware_Manual_guide/` on ADCD 2.1
|
||||
- ADCD 2.1: http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0000.html
|
||||
- AmigaMail Vol.2 — chipset programming articles
|
||||
69
01_hardware/aga_a1200_a4000/README.md
Normal file
69
01_hardware/aga_a1200_a4000/README.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md)
|
||||
|
||||
# AGA Chipset — A1200 / A4000 / CD32
|
||||
|
||||
## Overview
|
||||
|
||||
The **Advanced Graphics Architecture** (AGA) is the final custom chipset developed by Commodore, shipping from 1992. It dramatically expands colour depth, palette size, sprite capabilities, and blitter bandwidth while retaining full OCS/ECS backward compatibility.
|
||||
|
||||
## Chip Summary
|
||||
|
||||
| Chip | Name | Changes from ECS |
|
||||
|---|---|---|
|
||||
| **Alice** | MOS 8374 | Super Agnus successor: 64-bit bus, FMODE register |
|
||||
| **Lisa** | (unnamed MOS) | ECS Denise successor: 8-bit palette, 256 colours |
|
||||
| **Paula** | MOS 8364 | Unchanged from OCS/ECS |
|
||||
|
||||
## Contents
|
||||
|
||||
| File | Topic |
|
||||
|---|---|
|
||||
| [chipset_aga.md](chipset_aga.md) | Alice and Lisa internals, AGA architecture |
|
||||
| [aga_registers_delta.md](aga_registers_delta.md) | New/changed registers vs ECS |
|
||||
| [aga_palette.md](aga_palette.md) | 24-bit colour system, 256 registers |
|
||||
| [aga_display_modes.md](aga_display_modes.md) | HAM8, 256-colour, doublescan, VGA |
|
||||
| [aga_blitter.md](aga_blitter.md) | 64-bit blitter bus, FMODE |
|
||||
| [cpu_030_040.md](cpu_030_040.md) | 68030/040 on A3000/A4000: cache, MMU, FPU |
|
||||
| [gayle_ide_a1200.md](gayle_ide_a1200.md) | A1200 Gayle: IDE and PCMCIA specifics |
|
||||
|
||||
## AGA vs ECS — Key Differences
|
||||
|
||||
| Feature | ECS | AGA |
|
||||
|---|---|---|
|
||||
| Colour registers | 32 (12-bit) | **256 (24-bit)** |
|
||||
| Max simultaneous colours | 64 EHB / HAM | **256** (or HAM8: 262,144) |
|
||||
| Blitter bus | 16-bit | **64-bit** (FMODE) |
|
||||
| Sprite width | 16 px | **64 px** |
|
||||
| Sprite colours | 3+transparent | **15+transparent** (64-colour attached) |
|
||||
| Bitplane depth | 6 planes max | **8 planes** |
|
||||
| Palette select | 1 bank | **4 bitplane banks, 4 sprite banks** |
|
||||
|
||||
## Identifying AGA at Runtime
|
||||
|
||||
```c
|
||||
#include <graphics/gfxbase.h>
|
||||
|
||||
extern struct GfxBase *GfxBase;
|
||||
|
||||
BOOL is_aga = (GfxBase->ChipRevBits0 & (1 << GFXB_AA_ALICE)) != 0;
|
||||
```
|
||||
|
||||
| ChipRevBits0 bit | Flag | Meaning |
|
||||
|---|---|---|
|
||||
| 4 | `GFXB_AA_ALICE` | AGA Alice present |
|
||||
| 5 | `GFXB_AA_LISA` | AGA Lisa present |
|
||||
|
||||
## AGA Machines
|
||||
|
||||
| Model | CPU | Notes |
|
||||
|---|---|---|
|
||||
| A1200 | 68020 14 MHz | Budget AGA; Gayle IDE; PCMCIA; 2 MB Chip |
|
||||
| A4000 | 68030/040 25 MHz | High-end; Zorro III; IDE; 2 MB Chip + Fast |
|
||||
| A4000T | 68040/060 | Tower variant; SCSI |
|
||||
| CD32 | 68020 14 MHz | Game console; CD-ROM; SX-1 expansion |
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — AGA chapters
|
||||
- NDK39: `graphics/gfxbase.h`, `hardware/custom.h`
|
||||
- Commodore A1200/A4000 Technical Reference Manuals (local archive)
|
||||
167
01_hardware/aga_a1200_a4000/aga_blitter.md
Normal file
167
01_hardware/aga_a1200_a4000/aga_blitter.md
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# AGA Blitter — What It Is, What It Does, and 64-bit Bus Mode
|
||||
|
||||
## What Is the Blitter?
|
||||
|
||||
The **Blitter** (Block Image Transfer) is a dedicated DMA hardware engine inside every Amiga, designed to move and transform rectangular blocks of bitmap data **without CPU intervention**. While the CPU handles game logic, AI, physics, and sound setup, the Blitter does the heavy graphical lifting in the background.
|
||||
|
||||
Think of it as a **hardware GPU for 2D raster operations** — years before PC graphics cards existed.
|
||||
|
||||
### What the Blitter Can Do
|
||||
|
||||
| Capability | Description | Typical Use |
|
||||
|---|---|---|
|
||||
| **Block copy** | Move rectangular bitmap regions | Scrolling backgrounds, restoring screen areas |
|
||||
| **Cookie-cut blit** | Stamp a shape onto a background using a mask | Drawing game sprites (BOBs) with transparency |
|
||||
| **Area fill** | Fill arbitrary shapes | Flood-filling polygons, UI element backgrounds |
|
||||
| **Line drawing** | Draw lines using hardware Bresenham | Vector graphics, wireframe 3D |
|
||||
| **Clear/set memory** | Zero or fill large memory blocks | Screen clearing between frames |
|
||||
| **Logic operations** | Combine 3 inputs with any Boolean function | XOR cursors, shadow effects, masking |
|
||||
| **Shifting** | Shift source data 0–15 pixels | Sub-word-aligned sprite positioning |
|
||||
|
||||
### What the Blitter Cannot Do
|
||||
|
||||
| Limitation | Detail |
|
||||
|---|---|
|
||||
| No scaling | Cannot resize images — fixed 1:1 pixel mapping |
|
||||
| No rotation | Cannot rotate — must be pre-rendered in software |
|
||||
| No 3D | No perspective, texture mapping, or Z-buffer |
|
||||
| No chunky pixels | Operates on **planar** bitplanes only (1 plane at a time) |
|
||||
| No colour blending | Pure Boolean logic — no alpha, no transparency gradients |
|
||||
| Word-aligned width | Minimum operation width is 16 pixels (1 word) |
|
||||
|
||||
### How Software Uses It
|
||||
|
||||
**Games** — The blitter draws BOBs (Blitter Objects = software sprites) by cookie-cutting character graphics onto the playfield. A typical game frame:
|
||||
1. Blitter restores background behind old sprite positions
|
||||
2. Game logic updates positions
|
||||
3. Blitter draws sprites at new positions using cookie-cut
|
||||
4. Copper switches display to the newly drawn buffer (double-buffering)
|
||||
|
||||
**Demos** — Demoscene coders exploit every blitter trick: interleaved bitplane blits, fill-mode for filled vector polygons, line-mode for wireframes, and careful DMA scheduling to run blitter and CPU in parallel.
|
||||
|
||||
**Applications** — Workbench uses `BltBitMap()` for window dragging, scrolling text, and refreshing damaged screen areas. The `layers.library` damage repair system depends entirely on blitter operations.
|
||||
|
||||
---
|
||||
|
||||
## AGA Enhancements
|
||||
|
||||
AGA's Alice chip extends the blitter with a **64-bit data bus mode** controlled by the `FMODE` register. This allows the blitter to fetch 2 or 4 words per DMA cycle, dramatically increasing fill and copy throughput for large bitmap operations.
|
||||
|
||||
## FMODE Configuration
|
||||
|
||||
`FMODE` ($DFF1FC) controls blitter, bitplane, and sprite DMA fetch widths independently:
|
||||
|
||||
```
|
||||
bits 9-8: BLT_FMODE — blitter fetch mode
|
||||
00 = 16-bit (OCS compatible)
|
||||
01 = 32-bit
|
||||
10 = 64-bit
|
||||
11 = reserved
|
||||
|
||||
bits 13-12: BPL_FMODE — bitplane fetch mode (same encoding)
|
||||
bits 15-14: SPR_FMODE — sprite fetch mode (same encoding)
|
||||
```
|
||||
|
||||
Setting 64-bit blitter mode:
|
||||
```asm
|
||||
move.w #$0300, $DFF1FC ; BLT_FMODE = 10 (64-bit)
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> FMODE must be set **before** loading blitter registers and starting the blit. Changing FMODE mid-blit causes undefined behaviour.
|
||||
|
||||
## Width Calculation with FMODE
|
||||
|
||||
When using wider fetch modes, **BLTSIZE widths must be adjusted**:
|
||||
|
||||
| FMODE | Width unit | Width formula |
|
||||
|---|---|---|
|
||||
| 1× (16-bit) | 1 word = 16 bits | `width_in_words` |
|
||||
| 2× (32-bit) | 2 words = 32 bits | `(width_in_words + 1) / 2` |
|
||||
| 4× (64-bit) | 4 words = 64 bits | `(width_in_words + 3) / 4` |
|
||||
|
||||
Example: blitting 320 pixels wide (20 words):
|
||||
- 1× mode: BLTSIZE width = 20
|
||||
- 2× mode: BLTSIZE width = 10
|
||||
- 4× mode: BLTSIZE width = 5
|
||||
|
||||
**Modulo values are still in bytes** regardless of FMODE.
|
||||
|
||||
## Performance Comparison
|
||||
|
||||
For a typical 320×200 blit (simple copy, 1 bitplane):
|
||||
|
||||
| Mode | FMODE | Approx time (7 MHz) |
|
||||
|---|---|---|
|
||||
| OCS/ECS | 1× | ~1.8 ms |
|
||||
| AGA 2× | 2× | ~0.9 ms |
|
||||
| AGA 4× | 4× | ~0.45 ms |
|
||||
|
||||
## Alignment Requirements
|
||||
|
||||
Wider fetch modes impose alignment constraints on source/destination pointers:
|
||||
|
||||
| FMODE | Required alignment |
|
||||
|---|---|
|
||||
| 1× | 2 bytes (word) |
|
||||
| 2× | 4 bytes (long) |
|
||||
| 4× | 8 bytes (quadword) |
|
||||
|
||||
Misaligned pointers with 2× or 4× FMODE produce incorrect blit results.
|
||||
|
||||
## Using graphics.library
|
||||
|
||||
The OS `BltBitMap()` / `BltBitMapRastPort()` calls are FMODE-aware in OS 3.1+ on AGA hardware:
|
||||
|
||||
```c
|
||||
BltBitMap(src_bm, srcx, srcy, dst_bm, dstx, dsty, width, height,
|
||||
0xC0, 0xFF, NULL); /* minterm $C0 = copy, all planes */
|
||||
```
|
||||
|
||||
`graphics.library` automatically selects the optimal FMODE for the current hardware.
|
||||
|
||||
## BLTCON0 / BLTCON1 — Unchanged in AGA
|
||||
|
||||
The minterm logic (`BLTCON0`) and fill/line mode (`BLTCON1`) registers are functionally identical to OCS/ECS. AGA only adds bandwidth, not new logical capabilities.
|
||||
|
||||
## Direct AGA Blitter Example (64-bit clear)
|
||||
|
||||
```asm
|
||||
; Clear 320×256 bitmap at address $100000 (20 words wide, 256 lines)
|
||||
; Using AGA 4× FMODE (5 quads wide)
|
||||
|
||||
move.w #$0300, $DFF1FC ; FMODE: BLT_FMODE = 4×
|
||||
|
||||
move.w #$0100, BLTCON0+custom ; USE D only, minterm $00 (fill with zero)
|
||||
move.w #$0000, BLTCON1+custom
|
||||
|
||||
move.w #$FFFF, BLTAFWM+custom ; first word mask
|
||||
move.w #$FFFF, BLTALWM+custom ; last word mask
|
||||
|
||||
move.l #$00100000, BLTDPTH+custom+$00 ; dest high word
|
||||
; (split into high/low)
|
||||
move.w #$0010, BLTDPTH+custom
|
||||
move.w #$0000, BLTDPTL+custom
|
||||
|
||||
move.w #0, BLTDMOD+custom ; modulo = 0 (contiguous)
|
||||
|
||||
; BLTSIZE = (256 lines << 6) | 5 quads width = (256*64)|5 = $4005
|
||||
move.w #((256<<6)|5), BLTSIZE+custom ; start blit
|
||||
|
||||
; wait for completion
|
||||
WaitBlit:
|
||||
btst #6, DMACONR+custom+1
|
||||
bne.s WaitBlit
|
||||
|
||||
; Restore FMODE to 1× for safety
|
||||
move.w #$0000, $DFF1FC
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — AGA blitter section
|
||||
- NDK39: `hardware/blit.h`, `hardware/custom.h`
|
||||
- Commodore A1200/A4000 Technical Reference Manuals — Alice section
|
||||
- graphics.library Autodocs: BltBitMap, BltClear
|
||||
371
01_hardware/aga_a1200_a4000/aga_copper.md
Normal file
371
01_hardware/aga_a1200_a4000/aga_copper.md
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# AGA Copper — What It Is, How It Works, and Programming Guide
|
||||
|
||||
## What Is the Copper?
|
||||
|
||||
The **Copper** (Co-Processor) is one of the most distinctive pieces of hardware in any computer ever built. It is a tiny, ultra-simple programmable DMA engine that executes a program — called a **copper list** — in perfect synchronisation with the video beam as it sweeps across the screen.
|
||||
|
||||
The Copper watches the beam position and can **write any value to any custom chip register at any specific screen position**. This single capability enables an astonishing range of visual effects.
|
||||
|
||||
### Why Does It Matter?
|
||||
|
||||
On a conventional computer, changing display parameters (colours, scroll positions, resolutions) requires the CPU to execute code at precisely the right moment. This is fragile, wastes CPU time, and is limited by interrupt latency.
|
||||
|
||||
The Copper does this **automatically, for free, with perfect timing** — every single frame, without any CPU involvement at all.
|
||||
|
||||
---
|
||||
|
||||
## Copper in the System Architecture
|
||||
|
||||
### Block Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ CHIP RAM (up to 2MB) │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────────┐ │
|
||||
│ │ Copper List │ │ Bitplane Data│ │ Sprite Data │ │
|
||||
│ │ (MOVE/WAIT/ │ │ (screen │ │ (hardware sprite │ │
|
||||
│ │ SKIP words) │ │ pixels) │ │ images) │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └──────────┬────────────────┘ │
|
||||
└─────────┼──────────────────┼─────────────────────┼──────────────────┘
|
||||
│ DMA read │ DMA read │ DMA read
|
||||
▼ ▼ ▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ AGNUS / ALICE (DMA Controller) │
|
||||
│ │
|
||||
│ ┌────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
|
||||
│ │ COPPER │ │ Bitplane │ │ Sprite DMA │ │
|
||||
│ │ Engine │ │ DMA Engine │ │ Engine │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ • Fetches │ │ Fetches 1-8 │ │ Fetches sprite │ │
|
||||
│ │ copper │ │ planes per │ │ data for 8 sprites │ │
|
||||
│ │ list via │ │ line from │ │ per line │ │
|
||||
│ │ DMA │ │ BPLxPT │ │ │ │
|
||||
│ │ • Compares │ │ pointers │ │ │ │
|
||||
│ │ beam pos │ │ │ │ │ │
|
||||
│ │ • Writes │ │ │ │ │ │
|
||||
│ │ to regs │ │ │ │ │ │
|
||||
│ └─────┬──────┘ └──────┬───────┘ └───────────┬───────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ┌─────┴──────────────────┴────────────────────────┴─────────┐ │
|
||||
│ │ BEAM COUNTER (V count, H count) │ │
|
||||
│ │ Increments every colour clock, resets each frame │ │
|
||||
│ │ PAL: 312 lines × 227 clocks NTSC: 262 × 227 │ │
|
||||
│ └───────────────────────────────────────────────────────────┘ │
|
||||
└──────────┬─────────────────────────────────────────────────────────┘
|
||||
│ register writes ($DFF000–$DFF1FE)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ DENISE / LISA (Video Encoder) │
|
||||
│ │
|
||||
│ Receives bitplane data + sprite data + colour register values │
|
||||
│ Composites them into a final pixel stream: │
|
||||
│ │
|
||||
│ ┌────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
|
||||
│ │ Bitplane │ │ Sprite │ │ Colour │ │ Playfield │ │
|
||||
│ │ Decode │→ │ Priority │→ │ Palette │→ │ Priority & │ │
|
||||
│ │ (planar→ │ │ Merge │ │ Lookup │ │ Genlock Control │ │
|
||||
│ │ index) │ │ │ │ (32/256) │ │ │ │
|
||||
│ └────────────┘ └──────────┘ └──────────┘ └────────┬─────────┘ │
|
||||
└───────────────────────────────────────────────────────┬─────────────┘
|
||||
│
|
||||
▼
|
||||
┌────────────┐
|
||||
│ RGB / DAC │
|
||||
│ → Monitor │
|
||||
└────────────┘
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────────┐
|
||||
│ M68K CPU │
|
||||
│ │
|
||||
│ • Can read/write the SAME custom registers as the Copper │
|
||||
│ • Can modify the copper list in Chip RAM at any time │
|
||||
│ • Shares the DMA bus with Copper (Agnus arbitrates) │
|
||||
│ • CPU is STALLED when DMA bus is busy (Chip RAM access only) │
|
||||
│ • Fast RAM access is NOT affected by DMA contention │
|
||||
└─────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Component Interactions
|
||||
|
||||
**Copper ↔ Chip RAM:**
|
||||
The Copper fetches its program (the copper list) from Chip RAM via DMA. It reads one instruction (2 words = 4 bytes) every 4 colour clocks. The copper list **must** reside in Chip RAM — it cannot be in Fast RAM because only Chip RAM is DMA-accessible.
|
||||
|
||||
**Copper ↔ Custom Registers:**
|
||||
When the Copper executes a MOVE instruction, it writes directly to a custom chip register (`$DFF000`–`$DFF1FE`). This is the exact same register space the CPU writes to. The Copper can set colours, bitplane pointers, sprite pointers, display window, scroll offsets, DMA control, and audio parameters.
|
||||
|
||||
**Copper ↔ Beam Counter:**
|
||||
The Copper continuously compares the current beam position (V count, H count) against WAIT instructions. When the beam reaches or passes the specified position, execution continues. This is a hardware comparator — no polling loop, no interrupt latency.
|
||||
|
||||
**Copper ↔ CPU:**
|
||||
- They share the DMA bus. Agnus arbitrates: DMA engines get priority, CPU gets remaining cycles
|
||||
- The CPU can modify copper list words in Chip RAM; changes take effect on the next frame (or immediately if the Copper hasn't read that instruction yet)
|
||||
- The CPU can set `COP1LC`/`COP2LC` to change which copper list runs
|
||||
- The CPU can strobe `COPJMP1`/`COPJMP2` to restart the Copper mid-frame
|
||||
- The CPU is **not interrupted** by Copper activity — they are fully independent
|
||||
|
||||
**Copper ↔ Video Output:**
|
||||
The Copper doesn't produce video directly. It modifies the registers that Denise/Lisa uses to produce video. By changing registers at specific beam positions, the Copper indirectly controls what appears on every scanline.
|
||||
|
||||
**Copper ↔ Blitter:**
|
||||
A WAIT instruction with bit 15 of the mask word cleared becomes a "blitter-finished WAIT" — the Copper pauses until both the beam position is reached AND the blitter is idle. This coordinates copper list execution with blitter operations.
|
||||
|
||||
---
|
||||
|
||||
## What the Copper Can Do
|
||||
|
||||
| Effect | How | Used In |
|
||||
|---|---|---|
|
||||
| **Per-line colour changes** | WAIT for line, MOVE colour register | Gradient skies, rainbow bars |
|
||||
| **Split screens** | Change bitplane pointers mid-frame | Status bar + scrolling playfield |
|
||||
| **Parallax scrolling** | Change BPLCON1 (scroll offset) at different lines | Multi-layer side-scrollers |
|
||||
| **Resolution changes** | Change BPLCON0 mid-frame | HiRes menu + LoRes game area |
|
||||
| **Sprite multiplexing** | Repoint sprite DMA pointers after sprite finishes | More than 8 sprites per frame |
|
||||
| **Palette animation** | Modify colour registers each frame | Cycling colours, water shimmer |
|
||||
| **Display window tricks** | Change DIWSTRT/DIWSTOP | Overscan, letterbox |
|
||||
| **Interlace tricks** | Toggle LOF bit | Custom interlace effects |
|
||||
|
||||
### What the Copper Cannot Do
|
||||
|
||||
| Limitation | Detail |
|
||||
|---|---|
|
||||
| No computation | Cannot add, subtract, compare, branch, or loop |
|
||||
| No memory read | Can only WRITE to registers, never read |
|
||||
| Write-only to custom regs | Cannot write to CPU memory, CIA, or Fast RAM |
|
||||
| Limited register set | Protected registers ($000–$03E) need `COPCON` unlock |
|
||||
| No sub-pixel timing | Horizontal resolution is 4 colour clocks (~8 low-res pixels) |
|
||||
| Vertical wrapping | V counter wraps at 255; PAL lines 256+ need two WAITs |
|
||||
|
||||
---
|
||||
|
||||
## Instruction Set
|
||||
|
||||
The Copper has exactly **3 instructions**. Each is 32 bits (two 16-bit words):
|
||||
|
||||
### MOVE — Write Value to Register
|
||||
|
||||
```
|
||||
Word 1: 0RRRRRRR RR000000 R = register offset ($040–$1FE, even)
|
||||
Word 2: DDDDDDDD DDDDDDDD D = 16-bit data to write
|
||||
|
||||
Example: Set COLOR00 ($180) to bright red ($0F00):
|
||||
dc.w $0180, $0F00
|
||||
```
|
||||
|
||||
The register address in word 1 is the offset from `$DFF000`. Bit 0 of word 1 is always 0 (this distinguishes MOVE from WAIT/SKIP).
|
||||
|
||||
### WAIT — Wait for Beam Position
|
||||
|
||||
```
|
||||
Word 1: VVVVVVVV HHHHHHHH V = vertical beam (8 bits), H = horizontal
|
||||
Bit 0 = 1 (marks this as WAIT, not MOVE)
|
||||
Word 2: vvvvvvvv hhhhhhhm v,h = mask bits, m = 0 for WAIT
|
||||
(bit 0 of word 2 = 0 distinguishes from SKIP)
|
||||
|
||||
Example: Wait for line 100 ($64), any horizontal position:
|
||||
dc.w $6401, $FFFE
|
||||
```
|
||||
|
||||
The mask controls which beam position bits are compared. `$FFFE` means "match all bits" (standard). You can mask horizontal bits to wait for a specific column.
|
||||
|
||||
### SKIP — Conditional Skip
|
||||
|
||||
```
|
||||
Same format as WAIT, but bit 0 of word 2 = 1.
|
||||
If beam ≥ specified position, skip the next instruction.
|
||||
|
||||
Example: Skip next if beam is past line 200:
|
||||
dc.w $C801, $FFFF ; SKIP if V ≥ $C8
|
||||
dc.w $0180, $0F00 ; this MOVE is skipped if condition met
|
||||
```
|
||||
|
||||
### End of List
|
||||
|
||||
```
|
||||
dc.w $FFFF, $FFFE ; WAIT for impossible position (V=$FF, H=$FF)
|
||||
; Copper halts until next frame
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Your First Copper List
|
||||
|
||||
Here's the simplest possible copper list — it changes the background colour at line 128:
|
||||
|
||||
```asm
|
||||
SECTION copperlist,DATA_C ; *** MUST be in Chip RAM! ***
|
||||
|
||||
MyCopperList:
|
||||
; Top half: blue background
|
||||
dc.w $0180, $005F ; MOVE COLOR00 = blue
|
||||
|
||||
; Wait for middle of screen
|
||||
dc.w $8001, $FFFE ; WAIT line 128
|
||||
|
||||
; Bottom half: red background
|
||||
dc.w $0180, $0F00 ; MOVE COLOR00 = red
|
||||
|
||||
; End of list
|
||||
dc.w $FFFF, $FFFE ; WAIT forever
|
||||
```
|
||||
|
||||
To activate it:
|
||||
```asm
|
||||
lea $DFF000,a5
|
||||
move.l #MyCopperList,$080(a5) ; COP1LCH = pointer to our list
|
||||
move.w d0,$088(a5) ; COPJMP1 strobe = restart copper
|
||||
move.w #$8280,$096(a5) ; DMACON: enable Copper + Master DMA
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rainbow Gradient (Colour Per Scanline)
|
||||
|
||||
```asm
|
||||
RainbowCopper:
|
||||
dc.w $2C01,$FFFE ; WAIT line 44 (first visible PAL line)
|
||||
dc.w $0180,$0F00 ; red
|
||||
dc.w $2D01,$FFFE ; line 45
|
||||
dc.w $0180,$0E10
|
||||
dc.w $2E01,$FFFE ; line 46
|
||||
dc.w $0180,$0D20
|
||||
dc.w $2F01,$FFFE ; line 47
|
||||
dc.w $0180,$0C30
|
||||
dc.w $3001,$FFFE ; line 48
|
||||
dc.w $0180,$0B40
|
||||
dc.w $3101,$FFFE ; line 49
|
||||
dc.w $0180,$0A50
|
||||
dc.w $3201,$FFFE ; line 50
|
||||
dc.w $0180,$0960
|
||||
; ... continue for each line ...
|
||||
dc.w $FFFF,$FFFE
|
||||
```
|
||||
|
||||
This produces a smooth colour gradient down the screen — **zero CPU cost**.
|
||||
|
||||
---
|
||||
|
||||
## Parallax Scrolling (Per-Layer Scroll Speed)
|
||||
|
||||
```asm
|
||||
ParallaxCopper:
|
||||
; Sky layer (no scroll)
|
||||
dc.w $0102,$0000 ; BPLCON1 = 0 (no shift)
|
||||
|
||||
; Wait for horizon
|
||||
dc.w $6001,$FFFE ; WAIT line 96
|
||||
|
||||
; Hills layer (scroll slow)
|
||||
dc.w $0102,$0022 ; BPLCON1 = shift 2 pixels
|
||||
|
||||
; Wait for ground
|
||||
dc.w $A001,$FFFE ; WAIT line 160
|
||||
|
||||
; Ground layer (scroll fast)
|
||||
dc.w $0102,$0066 ; BPLCON1 = shift 6 pixels
|
||||
|
||||
dc.w $FFFF,$FFFE
|
||||
```
|
||||
|
||||
Each frame, a VBlank interrupt updates the scroll values in the copper list. The CPU just modifies 3 words — the Copper handles all the per-line register changes.
|
||||
|
||||
---
|
||||
|
||||
## Sprite Multiplexing
|
||||
|
||||
The Amiga has 8 hardware sprites, but the Copper can repoint them mid-frame for more:
|
||||
|
||||
```asm
|
||||
; Sprite 0 shows character A at Y=50
|
||||
dc.w $3001,$FFFE ; WAIT before sprite starts
|
||||
dc.w $0120,SprDataA>>16 ; SPR0PTH
|
||||
dc.w $0122,SprDataA ; SPR0PTL
|
||||
|
||||
; After sprite A finishes (Y=66), reuse for character B at Y=120
|
||||
dc.w $7801,$FFFE ; WAIT line 120
|
||||
dc.w $0120,SprDataB>>16 ; SPR0PTH = new sprite data
|
||||
dc.w $0122,SprDataB ; SPR0PTL
|
||||
|
||||
; After character B finishes, reuse for character C...
|
||||
dc.w $A001,$FFFE
|
||||
dc.w $0120,SprDataC>>16
|
||||
dc.w $0122,SprDataC
|
||||
```
|
||||
|
||||
This gives you **24+ sprites** on screen (8 physical × 3+ reuses per frame).
|
||||
|
||||
---
|
||||
|
||||
## System-Friendly Copper (OS API)
|
||||
|
||||
If your program coexists with Workbench, use `graphics.library`:
|
||||
|
||||
```c
|
||||
struct UCopList *ucl = AllocMem(sizeof(struct UCopList), MEMF_CLEAR);
|
||||
|
||||
CINIT(ucl, 50); /* init, max 50 instructions */
|
||||
CWAIT(ucl, 0, 0); /* wait top of screen */
|
||||
CMOVE(ucl, custom.color[0], 0x005F); /* COLOR00 = blue */
|
||||
CWAIT(ucl, 128, 0); /* wait line 128 */
|
||||
CMOVE(ucl, custom.color[0], 0x0F00); /* COLOR00 = red */
|
||||
CEND(ucl); /* end */
|
||||
|
||||
viewport->UCopIns = ucl;
|
||||
RethinkDisplay(); /* merge into system copper list */
|
||||
```
|
||||
|
||||
The OS inserts your instructions into its own copper list, interleaved with its own display management.
|
||||
|
||||
---
|
||||
|
||||
## AGA Copper Enhancements
|
||||
|
||||
AGA (Alice chip) keeps the same 3-instruction Copper but gains access to the **extended AGA registers**:
|
||||
|
||||
| AGA Feature | Copper Can Set |
|
||||
|---|---|
|
||||
| 256-colour palette | `COLOR00–COLOR255` via BPLCON3 bank select |
|
||||
| Extended sprites | 64-colour sprites via palette banks |
|
||||
| FMODE | DMA fetch width (but careful — affects in-progress DMA) |
|
||||
| BPLCON3/BPLCON4 | AGA-specific bitplane/sprite control |
|
||||
|
||||
### AGA Palette via Copper
|
||||
|
||||
AGA has 256 colours but still only 32 colour registers visible at a time. To load all 256 colours, the Copper uses BPLCON3 to select palette banks:
|
||||
|
||||
```asm
|
||||
; Load colours 0–31 (bank 0)
|
||||
dc.w $0106,$0000 ; BPLCON3: bank 0
|
||||
dc.w $0180,$0000 ; COLOR00
|
||||
dc.w $0182,$0111 ; COLOR01
|
||||
; ... all 32 colours ...
|
||||
|
||||
; Switch to bank 1 (colours 32–63)
|
||||
dc.w $0106,$2000 ; BPLCON3: bank 1
|
||||
dc.w $0180,$0222 ; COLOR32
|
||||
dc.w $0182,$0333 ; COLOR33
|
||||
; ... etc for all 8 banks ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Copper Timing
|
||||
|
||||
| Parameter | Value |
|
||||
|---|---|
|
||||
| Instruction time | 4 colour clocks (= 8 lo-res pixels = ~1.12 µs) |
|
||||
| Max instructions per line | ~112 (NTSC) / ~114 (PAL) |
|
||||
| Horizontal resolution | 4 colour clocks (~8 lo-res pixels) |
|
||||
| Vertical range | 0–255 (wraps; use double-WAIT for PAL lines 256+) |
|
||||
| PAL visible lines | 44–300 (256 visible) |
|
||||
| NTSC visible lines | 44–244 (200 visible) |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- HRM: *Copper* chapter — authoritative register descriptions
|
||||
- `08_graphics/copper.md` — graphics.library UCopList API
|
||||
- `08_graphics/copper_programming.md` — additional examples
|
||||
- `01_hardware/ocs_a500/copper.md` — OCS-level register reference
|
||||
122
01_hardware/aga_a1200_a4000/aga_display_modes.md
Normal file
122
01_hardware/aga_a1200_a4000/aga_display_modes.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# AGA Display Modes
|
||||
|
||||
## Overview
|
||||
|
||||
AGA introduces several new display modes and extends existing ones, enabled via the OS **screenmode** system (`graphics/modeid.h`) and `OpenScreenTags()`.
|
||||
|
||||
## Mode ID System
|
||||
|
||||
AmigaOS uses 32-bit **ModeIDs** to identify display modes. The format is:
|
||||
```
|
||||
[Monitor ID (16 bits)] | [Mode flags (16 bits)]
|
||||
```
|
||||
|
||||
Key AGA monitor IDs:
|
||||
```c
|
||||
#define PAL_MONITOR_ID 0x00000000
|
||||
#define NTSC_MONITOR_ID 0x00010000
|
||||
#define A2024_MONITOR_ID 0x00020000
|
||||
#define VGA_MONITOR_ID 0x00031000 /* ECS productivity */
|
||||
#define A2024_10HZ_ID 0x00040000
|
||||
#define DBLPAL_MONITOR_ID 0x00420000 /* AGA double PAL */
|
||||
#define DBLNTSC_MONITOR_ID 0x00400000 /* AGA double NTSC */
|
||||
#define SUPER72_MONITOR_ID 0x00080000
|
||||
```
|
||||
|
||||
Mode flags (lower 16 bits):
|
||||
```c
|
||||
#define LORES_KEY 0x0000 /* 320 wide (PAL) */
|
||||
#define HIRES_KEY 0x8000 /* 640 wide */
|
||||
#define HAM_KEY 0x0800 /* HAM mode */
|
||||
#define EXTRAHALFBRITE_KEY 0x0080 /* EHB */
|
||||
#define LACE_KEY 0x0004 /* interlace */
|
||||
```
|
||||
|
||||
## Standard AGA Modes
|
||||
|
||||
| Mode ID | Resolution | Colours | H rate |
|
||||
|---|---|---|---|
|
||||
| `PAL_MONITOR_ID \| LORES_KEY` | 320×256 | 256 | 15.6 kHz |
|
||||
| `PAL_MONITOR_ID \| HIRES_KEY` | 640×256 | 256 | 15.6 kHz |
|
||||
| `PAL_MONITOR_ID \| HIRES_KEY \| LACE_KEY` | 640×512 | 256 | 15.6 kHz (interlace) |
|
||||
| `DBLPAL_MONITOR_ID \| LORES_KEY` | 320×512 | 256 | 31.25 kHz |
|
||||
| `DBLPAL_MONITOR_ID \| HIRES_KEY` | 640×512 | 256 | 31.25 kHz |
|
||||
| `PAL_MONITOR_ID \| LORES_KEY \| HAM_KEY` | 320×256 | 262,144 (HAM8) | 15.6 kHz |
|
||||
| `SUPER72_MONITOR_ID \| HIRES_KEY` | 800×600 (approx) | 256 | 28+ kHz |
|
||||
|
||||
## Opening an AGA Screen (OS 3.1)
|
||||
|
||||
```c
|
||||
#include <intuition/screens.h>
|
||||
#include <graphics/modeid.h>
|
||||
#include <proto/intuition.h>
|
||||
|
||||
struct Screen *scr;
|
||||
|
||||
/* 256-colour AGA screen, PAL, 320×256 */
|
||||
scr = OpenScreenTags(NULL,
|
||||
SA_DisplayID, PAL_MONITOR_ID | LORES_KEY,
|
||||
SA_Width, 320,
|
||||
SA_Height, 256,
|
||||
SA_Depth, 8, /* 8 bitplanes = 256 colours */
|
||||
SA_Colors32, (ULONG)colour_table, /* LoadRGB32 format */
|
||||
SA_Title, (ULONG)"My AGA Screen",
|
||||
SA_Quiet, TRUE,
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
## HAM8 Screen
|
||||
|
||||
```c
|
||||
scr = OpenScreenTags(NULL,
|
||||
SA_DisplayID, PAL_MONITOR_ID | LORES_KEY | HAM_KEY,
|
||||
SA_Width, 320,
|
||||
SA_Height, 256,
|
||||
SA_Depth, 8,
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> HAM8 screens require 8 bitplanes. The display system automatically programmes BPLCON0 with HAM=1. The first 64 colour registers are used as the HAM8 index palette.
|
||||
|
||||
## BestModeID() — Querying Available Modes
|
||||
|
||||
```c
|
||||
#include <proto/graphics.h>
|
||||
|
||||
ULONG modeid = BestModeID(
|
||||
BIDTAG_NominalWidth, 640,
|
||||
BIDTAG_NominalHeight, 512,
|
||||
BIDTAG_Depth, 8,
|
||||
BIDTAG_MonitorID, DBLPAL_MONITOR_ID,
|
||||
TAG_DONE);
|
||||
|
||||
if (modeid == INVALID_ID) {
|
||||
/* Requested mode not available */
|
||||
}
|
||||
```
|
||||
|
||||
## Double Scan Modes (DblPAL / DblNTSC)
|
||||
|
||||
`DBLPAL` and `DBLNTSC` modes use AGA's scan doubler to produce non-interlaced 31 kHz output from PAL/NTSC timing:
|
||||
|
||||
- DblPAL: 320×512 or 640×512, 31.25 kHz — compatible with VGA monitors
|
||||
- DblNTSC: 320×400 or 640×400, 31.47 kHz
|
||||
|
||||
These require a multisync monitor and AGA chipset. The A1200 can drive a 1084S in scan-doubled mode.
|
||||
|
||||
## Super72 Mode
|
||||
|
||||
Super72 provides approximately 800×600 resolution at ~28 kHz horizontal:
|
||||
- Used by some Workbench productivity configurations
|
||||
- Requires multisync monitor
|
||||
- Available via `SUPER72_MONITOR_ID`
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/modeid.h` — all monitor and mode ID definitions
|
||||
- ADCD 2.1: `Libraries_Manual_guide/` — graphics.library OpenScreen
|
||||
- Autodocs: `BestModeID`, `OpenScreenTags`
|
||||
- AmigaMail Vol. 2 — AGA display mode programming
|
||||
134
01_hardware/aga_a1200_a4000/aga_palette.md
Normal file
134
01_hardware/aga_a1200_a4000/aga_palette.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# AGA Palette & Colour System
|
||||
|
||||
## Overview
|
||||
|
||||
AGA provides **256 colour registers** (COLOR00–COLOR255), each **24-bit RGB** (8 bits per channel). This replaces OCS/ECS's 32 registers with 12-bit colour.
|
||||
|
||||
## Colour Register Layout
|
||||
|
||||
```
|
||||
ADDRESS: $DFF180 + (n × 2) for register n (0–255)
|
||||
```
|
||||
|
||||
AGA extends the register space:
|
||||
```
|
||||
$DFF180–$DFF1BE COLOR00–COLOR31 (same addresses as OCS/ECS)
|
||||
$DFF180–$DFF3BE COLOR00–COLOR255 (full AGA range — needs BPLCON4 bank select)
|
||||
```
|
||||
|
||||
The 256 colour registers are accessed in 64-register **banks** selected by `BPLCON4`.
|
||||
|
||||
## Writing 24-bit Colours
|
||||
|
||||
Each colour register holds 12 bits directly (OCS/ECS compatible). The upper 12 bits (the "low nibble") are written via a second access with `LOCT` set in BPLCON3.
|
||||
|
||||
### Manual 24-bit write sequence:
|
||||
|
||||
```asm
|
||||
; Write color $FF8040 (R=$FF, G=$80, B=$40) to COLOR00
|
||||
|
||||
; Step 1: Write high nibble ($F84 = top 4 bits of R,G,B)
|
||||
move.w #$0F84, COLOR00+custom ; $0RGB high nibble
|
||||
|
||||
; Step 2: Set LOCT bit in BPLCON3 to enable low nibble write
|
||||
bset #9, BPLCON3+custom+1 ; bit 9
|
||||
|
||||
; Step 3: Write low nibble ($F04 = low 4 bits of R,G,B → $0F, $08, $04 → $F84 again!)
|
||||
; Actually: low nibble of FF = F, low nibble of 80 = 0, low nibble of 40 = 0
|
||||
move.w #$0F00, COLOR00+custom ; low nibble
|
||||
|
||||
; Step 4: Clear LOCT
|
||||
bclr #9, BPLCON3+custom+1
|
||||
```
|
||||
|
||||
### Using LoadRGB32()
|
||||
|
||||
The preferred OS call:
|
||||
```c
|
||||
#include <graphics/view.h>
|
||||
#include <proto/graphics.h>
|
||||
|
||||
/* Table: count, index, then 0x00RRGGBB values, terminated by ~0 */
|
||||
ULONG table[] = {
|
||||
4, 0, /* 4 colours starting at index 0 */
|
||||
0x00FF0000, /* COLOR00: red */
|
||||
0x0000FF00, /* COLOR01: green */
|
||||
0x000000FF, /* COLOR02: blue */
|
||||
0x00FFFFFF, /* COLOR03: white */
|
||||
~0UL /* terminator */
|
||||
};
|
||||
LoadRGB32(viewport, table);
|
||||
```
|
||||
|
||||
`LoadRGB32()` (graphics.library LVO -$192) is the AGA-correct way to set colours. It handles the two-write LOCT protocol internally and is available from OS 3.0+.
|
||||
|
||||
### Using LoadRGB4() — OCS/ECS compatible (12-bit)
|
||||
|
||||
```c
|
||||
UWORD colours[32] = { 0x000, 0xF00, 0x0F0, ... };
|
||||
LoadRGB4(viewport, colours, 32); /* sets 32 colours from 12-bit table */
|
||||
```
|
||||
|
||||
`LoadRGB4()` is safe on all chipsets but only provides 12-bit precision on AGA.
|
||||
|
||||
## HAM8 Mode (Hold-And-Modify, 8-bit)
|
||||
|
||||
HAM8 is the AGA extension of OCS's HAM6. It uses 8 bitplanes:
|
||||
|
||||
- **Bits 7-6** of each pixel: mode select
|
||||
- `00` = index mode (look up COLOR00–COLOR63)
|
||||
- `01` = modify blue channel
|
||||
- `10` = modify red channel
|
||||
- `11` = modify green channel
|
||||
- **Bits 5-0**: 6-bit value for the selected channel (or 6-bit colour index)
|
||||
|
||||
Result: 2^18 = **262,144 simultaneous colours** from adjacent-pixel modification.
|
||||
|
||||
Enabling HAM8:
|
||||
```asm
|
||||
; BPLCON0: 8 planes (BPU=8, BPU3=1, BPU2-0=000), HAM=1, ECSENA=1
|
||||
move.w #$9811, BPLCON0+custom
|
||||
```
|
||||
|
||||
## Colour Modes Summary
|
||||
|
||||
| Mode | Planes | Colours | Method |
|
||||
|---|---|---|---|
|
||||
| Standard | 1–8 | 2–256 | Direct palette lookup |
|
||||
| EHB | 6 | 64 | Extra Half-Brite (OCS/ECS compat) |
|
||||
| HAM6 | 6 | 4096 | Hold-and-modify 4-bit channels |
|
||||
| HAM8 | 8 | 262,144 | Hold-and-modify 6-bit channels |
|
||||
| Dual Playfield | 3+3 | 8+8 | Two independent 8-colour layers |
|
||||
|
||||
## Colour Bank Selection (BPLCON4)
|
||||
|
||||
The 256 colour registers are split into 4 banks of 64:
|
||||
|
||||
| BPLAM | Bank | Registers |
|
||||
|---|---|---|
|
||||
| $00 | 0 | COLOR00–COLOR63 |
|
||||
| $40 | 1 | COLOR64–COLOR127 |
|
||||
| $80 | 2 | COLOR128–COLOR191 |
|
||||
| $C0 | 3 | COLOR192–COLOR255 |
|
||||
|
||||
Dual playfield can use BPLCON4 to give each playfield a different 64-colour bank.
|
||||
|
||||
## OS Colour Management
|
||||
|
||||
`graphics.library` manages palette via the `ColorMap` structure attached to a `ViewPort`:
|
||||
|
||||
```c
|
||||
struct ColorMap *cm = GetColorMap(256); /* allocate 256-entry AGA map */
|
||||
SetRGB32(vp, n, r, g, b); /* set one colour (24-bit each) */
|
||||
LoadRGB32(vp, table); /* bulk load */
|
||||
FreeColorMap(cm);
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/view.h` — ColorMap, LoadRGB32
|
||||
- ADCD 2.1 Autodocs: graphics — LoadRGB32, SetRGB32
|
||||
- http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node02B4.html
|
||||
- AmigaMail Vol. 2 — AGA colour system articles
|
||||
97
01_hardware/aga_a1200_a4000/aga_registers_delta.md
Normal file
97
01_hardware/aga_a1200_a4000/aga_registers_delta.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# AGA Register Deltas vs ECS
|
||||
|
||||
## New Registers
|
||||
|
||||
### FMODE — $DFF1FC (AGA only)
|
||||
|
||||
DMA fetch mode — see `chipset_aga.md` for full description.
|
||||
|
||||
### BPLCON4 — $DFF10C (AGA only)
|
||||
|
||||
Bitplane and sprite colour bank selection:
|
||||
|
||||
```
|
||||
bits 15-8: BPLAM7-0 — Bitplane XOR pattern (AGA colour bank XOR)
|
||||
bits 7-4: ESPRM7-4 — Even sprite colour bank (bits 7:4 of colour reg index)
|
||||
bits 3-0: OSPRM7-4 — Odd sprite colour bank
|
||||
```
|
||||
|
||||
**Bitplane bank select via BPLAM:**
|
||||
- BPLAM provides an XOR mask applied to the 8-bit colour index before palette lookup
|
||||
- BPLAM = $00 → use COLOR00–COLOR63 (bank 0)
|
||||
- BPLAM = $40 → use COLOR64–COLOR127 (bank 1)
|
||||
- BPLAM = $80 → use COLOR128–COLOR191 (bank 2)
|
||||
- BPLAM = $C0 → use COLOR192–COLOR255 (bank 3)
|
||||
|
||||
### COLOR00–COLOR255 — $DFF180–$DFF3BE (AGA)
|
||||
|
||||
AGA extends the colour table from 32 registers (OCS/ECS) to **256 registers**.
|
||||
|
||||
Each AGA colour register is 32 bits (accessed as two word writes via BPLCON3 latch):
|
||||
|
||||
```asm
|
||||
; Write 24-bit colour to COLOR00:
|
||||
; First write sets high nibble, second sets low nibble
|
||||
move.w #$0000, BPLCON3+custom ; set LACE=0, select low colour word
|
||||
move.w #$0FFF, COLOR00+custom ; write $RGB (high 12 bits)
|
||||
bset #9, BPLCON3_shadow ; set LOCT (low nibble enable)
|
||||
move.w #$0FFF, COLOR00+custom ; write low nibble of each channel
|
||||
```
|
||||
|
||||
The standard `LoadRGB32()` and `LoadRGB4()` graphics library calls manage this transparently.
|
||||
|
||||
## Changed Registers
|
||||
|
||||
### BPLCON2 — $DFF104 (AGA extended)
|
||||
|
||||
```
|
||||
bits 14-9: KILLEHB — kill EHB mode (AGA replaces EHB with 256 colour)
|
||||
bit 6: RDRAM — read bitplane data from RAM (not registered in Lisa)
|
||||
bits 5-3: PF2PRI — playfield 2 priority
|
||||
bits 2-0: PF1PRI — playfield 1 priority + sprite priority
|
||||
```
|
||||
|
||||
### BPLCON3 — $DFF106 (AGA extended from ECS)
|
||||
|
||||
Additional AGA bits:
|
||||
```
|
||||
bit 9: LOCT — low colour write enable (for 24-bit colour access)
|
||||
bit 3: BRDSPRT — sprites visible in border
|
||||
```
|
||||
|
||||
## AGA-Specific BPLCON0 Bits
|
||||
|
||||
See `chipset_aga.md` — bit 4 is the MSB of the bitplane count for 7/8-plane modes.
|
||||
|
||||
## Colour Register Access — Low Nibble Protocol
|
||||
|
||||
Writing 24-bit colour to AGA registers requires two steps per colour:
|
||||
|
||||
1. **Write high nibble** (standard): `COLOR00 = $0RGB` (bits [11:0] = R[3:0], G[3:0], B[3:0])
|
||||
2. **Set LOCT** in BPLCON3 (bit 9)
|
||||
3. **Write low nibble**: `COLOR00 = $0rgb` (bits [11:0] = R[3:0], G[3:0], B[3:0], these are the low 4 bits)
|
||||
|
||||
This two-write sequence gives 8 bits per channel (R[7:0], G[7:0], B[7:0]) = 24-bit colour.
|
||||
|
||||
`LoadRGB32()` does this automatically:
|
||||
```c
|
||||
/* AGA 32-bit colour table format:
|
||||
Count, then pairs: [colour_index, 0x00RRGGBB] */
|
||||
ULONG colour_table[] = {
|
||||
32, 0, /* 32 colours starting at index 0 */
|
||||
0x00FF0000, /* COLOR00 = red */
|
||||
0x0000FF00, /* COLOR01 = green */
|
||||
/* ... */
|
||||
~0UL /* terminator */
|
||||
};
|
||||
LoadRGB32(vp, colour_table);
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — AGA register appendix
|
||||
- NDK39: `hardware/custom.h`, `graphics/view.h`
|
||||
- Commodore A1200/A4000 Technical Reference Manuals
|
||||
- AmigaMail Vol. 2 — AGA colour programming
|
||||
120
01_hardware/aga_a1200_a4000/chipset_aga.md
Normal file
120
01_hardware/aga_a1200_a4000/chipset_aga.md
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# AGA Chipset Internals — Alice & Lisa
|
||||
|
||||
## Alice (MOS 8374) — AGA Agnus
|
||||
|
||||
Alice is the successor to Super Agnus and is the DMA controller and Copper/Blitter engine for AGA machines.
|
||||
|
||||
### Key Enhancements over Super Agnus
|
||||
|
||||
**64-bit DMA fetch bus (FMODE):**
|
||||
Alice can fetch 2 or 4 words per DMA cycle via the `FMODE` register ($DFF1FC). This dramatically increases the bandwidth available to the blitter and bitplane DMA.
|
||||
|
||||
**Extended bitplane depth:**
|
||||
Alice supports up to **8 bitplanes** (256 colours), compared to OCS/ECS's 6-plane limit.
|
||||
|
||||
**BPLCON4:**
|
||||
Alice adds `BPLCON4` to control bitplane bank selection — which 64-entry block of the 256-entry colour table is used by the bitplanes.
|
||||
|
||||
### ALICE_ID
|
||||
|
||||
Alice can be identified via `VPOSR`:
|
||||
```asm
|
||||
move.w $DFF004, d0 ; VPOSR
|
||||
lsr.w #8, d0
|
||||
```
|
||||
|
||||
| VPOSR[15:8] | Chip |
|
||||
|---|---|
|
||||
| $22 | Alice AGA (standard) |
|
||||
| $23 | Alice AGA (some A4000 revisions) |
|
||||
|
||||
---
|
||||
|
||||
## Lisa (AGA Denise)
|
||||
|
||||
Lisa is the display chip successor to ECS Denise, providing 8-bit colour output (256 colour registers) and extended sprite capabilities.
|
||||
|
||||
### Key Enhancements over ECS Denise
|
||||
|
||||
**256 colour registers:**
|
||||
Lisa provides COLOR00–COLOR255, each 24-bit (32-bit register with low byte unused).
|
||||
|
||||
**4 colour banks for bitplanes:**
|
||||
`BPLCON4` selects which 64-register bank (0–3) the bitplanes use for lookup. This allows dual-playfield each using a different 64-colour palette.
|
||||
|
||||
**Sprite bank selection:**
|
||||
`BPLCON3` bits select which colour bank sprite pairs use.
|
||||
|
||||
**Extended sprite width:**
|
||||
Sprites can be 16 or 64 pixels wide in AGA mode.
|
||||
|
||||
**Lisa ID:**
|
||||
Readable from `$DFF07C` (DENISEID):
|
||||
```asm
|
||||
move.w $DFF07C, d0 ; DENISEID = $00F8 for AGA Lisa
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FMODE — DMA Fetch Width Register ($DFF1FC)
|
||||
|
||||
The most critical AGA-specific register. Controls the data bus width for blitter and bitplane DMA:
|
||||
|
||||
```
|
||||
bits 15-14: SPR_FMODE — sprite fetch mode
|
||||
bits 13-12: BPL_FMODE — bitplane fetch mode
|
||||
bits 9-8: BLT_FMODE — blitter fetch mode
|
||||
|
||||
00 = 1× (16-bit, OCS/ECS compatible)
|
||||
01 = 2× (32-bit)
|
||||
10 = 4× (64-bit)
|
||||
11 = reserved
|
||||
```
|
||||
|
||||
**Setting full 64-bit blitter mode:**
|
||||
```asm
|
||||
move.w #$00C0, $DFF1FC ; FMODE: BLT_FMODE=11 (64-bit)
|
||||
; Also set BPL and SPR modes as needed
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> Writing FMODE on OCS/ECS machines writes to the `LISAID` location (read-only) — no hardware damage, but the read-back value is incorrect. Always verify AGA presence before writing FMODE.
|
||||
|
||||
---
|
||||
|
||||
## DMA Bandwidth with FMODE
|
||||
|
||||
| FMODE | Bus width | Blitter speed | Bitplane DMA |
|
||||
|---|---|---|---|
|
||||
| 1× (OCS compat) | 16-bit | 1× | 1× |
|
||||
| 2× | 32-bit | 2× | 2× |
|
||||
| 4× | 64-bit | 4× | 4× |
|
||||
|
||||
At 4× mode, the AGA blitter can fill/copy at ~70 MB/s theoretical on a 7 MHz bus.
|
||||
|
||||
---
|
||||
|
||||
## BPLCON0 Extended Bits (AGA)
|
||||
|
||||
In AGA mode, `BPLCON0` bit 4 (`ECSENA`) must be **1** to enable AGA features. Additional BPU bit (bit 4 of the count) allows 7 and 8 planes:
|
||||
|
||||
```
|
||||
bits 14-12: BPU2-0 — lower 3 bits of bitplane count
|
||||
bit 4: BPU3 — MSB of bitplane count (AGA: allows 7, 8 planes)
|
||||
```
|
||||
|
||||
To use 8 bitplanes (256 colours):
|
||||
```asm
|
||||
move.w #$9411, BPLCON0+custom ; HIRES=1 (if needed), BPU=8 (BPU3=1, BPU2-0=000), ECSENA=1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — AGA chapter
|
||||
- NDK39: `hardware/custom.h` — struct Custom (with AGA extensions)
|
||||
- Commodore A1200 Technical Reference Manual — Alice/Lisa section
|
||||
- AmigaMail Vol. 2 — AGA programming articles
|
||||
139
01_hardware/aga_a1200_a4000/cpu_030_040.md
Normal file
139
01_hardware/aga_a1200_a4000/cpu_030_040.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# 68030/040 on the Amiga (A3000/A4000)
|
||||
|
||||
## Overview
|
||||
|
||||
The A3000 ships with a **Motorola 68030** at 16 or 25 MHz. The A4000 ships with either a 68030 or **68040** at 25 MHz. Later accelerator cards bring the 68060. This document covers CPU-specific concerns for AmigaOS 3.1/3.2 on these platforms.
|
||||
|
||||
## 68030 (A3000)
|
||||
|
||||
### On-Chip Caches
|
||||
- **Instruction cache**: 256 bytes, direct-mapped
|
||||
- **Data cache**: 256 bytes, direct-mapped
|
||||
- Both enabled by default on AmigaOS 3.1 (`CacheControl()` call)
|
||||
|
||||
### On-Chip PMMU
|
||||
- Full 68030 PMMU: ATC (Address Translation Cache), TT registers
|
||||
- AmigaOS does **not** use the MMU by default on A3000
|
||||
- Third-party tools (e.g., VMM, mmu.library) use it for virtual memory
|
||||
|
||||
### Cache Control (exec)
|
||||
```c
|
||||
#include <proto/exec.h>
|
||||
|
||||
/* Enable instruction and data caches */
|
||||
CacheControl(CACRF_EnableI | CACRF_EnableD, CACRF_EnableI | CACRF_EnableD);
|
||||
|
||||
/* Flush caches (required before self-modifying code) */
|
||||
CacheClearU(); /* clear all caches */
|
||||
CacheClearE(addr, len, CACRF_ClearI | CACRF_ClearD); /* targeted flush */
|
||||
```
|
||||
|
||||
### Cache Coherency with DMA
|
||||
The 68030 data cache is **not snooped** by the Amiga chip bus. If the CPU writes to a buffer that the DMA engine (Blitter, audio, custom chips) will read, the cache must be flushed first:
|
||||
|
||||
```c
|
||||
/* Before handing a buffer to DMA: */
|
||||
CacheClearE(buf, size, CACRF_ClearD);
|
||||
```
|
||||
|
||||
Similarly, after DMA writes to a buffer that the CPU will read:
|
||||
```c
|
||||
CacheClearE(buf, size, CACRF_ClearD);
|
||||
```
|
||||
|
||||
This is a common source of bugs in audio/video programming on 68030+ Amigas.
|
||||
|
||||
---
|
||||
|
||||
## 68040 (A4000 / Accelerators)
|
||||
|
||||
### On-Chip FPU — Partial Implementation
|
||||
The 68040 has an on-chip FPU but omits many instructions present in the 68881/68882:
|
||||
|
||||
**Missing from 68040 FPU:**
|
||||
- `FSIN`, `FCOS`, `FTAN`, `FASIN`, `FACOS`, `FATAN`
|
||||
- `FETOX`, `FETOXM1`, `FLOGN`, `FLOG10`
|
||||
- `FSINH`, `FCOSH`, `FTANH`
|
||||
- `FATANH`, `FASINH`, `FACOSH`
|
||||
- `FSCALE`, `FREMX`, `FREMX`, `FINTRZ`
|
||||
|
||||
AmigaOS provides `68040.library` which installs Line-F exception handlers to emulate the missing instructions in software.
|
||||
|
||||
```c
|
||||
/* 68040.library is opened automatically by exec at boot */
|
||||
/* Software should check that it is open before using FP */
|
||||
struct Library *MathLib = OpenLibrary("68040.library", 0);
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> If `68040.library` is not installed and software uses a missing 68040 FPU instruction, the system will crash with a Line-F exception. Always ensure `68040.library` is present on A4000.
|
||||
|
||||
### 4 KB Instruction + Data Caches
|
||||
- 68040 has **4 KB instruction cache** and **4 KB data cache**, both 4-way set-associative
|
||||
- Cache coherency is more complex: DMA writes may not be visible to the CPU without invalidation
|
||||
- `CacheClearE()` / `CacheClearU()` remain the correct API
|
||||
|
||||
### 68040 Memory Model
|
||||
```
|
||||
CACR (Cache Control Register) accessed via MOVEC:
|
||||
bit 15: EDC — enable data cache
|
||||
bit 14: NAD — no allocate data (streaming mode)
|
||||
bit 13: ESB — enable store buffer
|
||||
bit 10: DPI — disable push-inhibit
|
||||
bit 7: EIC — enable instruction cache
|
||||
bit 3: CINV — cache invalidate
|
||||
```
|
||||
|
||||
### Bus Error Stack Frame (68040)
|
||||
The 68040 generates a **different bus error stack frame** from the 68000:
|
||||
- 68000: 14-byte frame
|
||||
- 68040: 104-byte frame with pipeline state
|
||||
|
||||
This matters for exception handlers and debuggers targeting both platforms.
|
||||
|
||||
---
|
||||
|
||||
## 68060 (Accelerator Cards)
|
||||
|
||||
Available via Blizzard 060, CyberStorm 060, etc. Key differences:
|
||||
|
||||
- **Superscalar**: two integer pipelines (in-order, no OOO)
|
||||
- **Branch prediction**: static and dynamic
|
||||
- **No MOVE16 snooping** on some Amiga implementations
|
||||
- On-chip FPU: missing same transcendentals as 68040 → needs `68060.library`
|
||||
- Separate `68060.library` for the additional missing instructions vs 68040
|
||||
|
||||
```c
|
||||
struct Library *Lib060 = OpenLibrary("68060.library", 0);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AmigaOS exec CacheControl() API
|
||||
|
||||
```c
|
||||
#include <exec/execbase.h>
|
||||
#include <proto/exec.h>
|
||||
|
||||
/* SysBase->CacheFlags reflect current cache state */
|
||||
ULONG flags = CacheControl(0, 0); /* query without changing */
|
||||
|
||||
/* Flag bits: */
|
||||
#define CACRF_EnableD (1L<<3) /* data cache enable */
|
||||
#define CACRF_FreezeD (1L<<4) /* data cache freeze */
|
||||
#define CACRF_ClearD (1L<<5) /* clear data cache */
|
||||
#define CACRF_EnableI (1L<<8) /* instruction cache enable */
|
||||
#define CACRF_FreezeI (1L<<9) /* instruction cache freeze */
|
||||
#define CACRF_ClearI (1L<<10) /* clear instruction cache */
|
||||
#define CACRF_CopyBack (1L<<31) /* data cache write-back mode */
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- Motorola 68030 User's Manual (M68030UM/AD)
|
||||
- Motorola 68040 User's Manual (M68040UM/AD)
|
||||
- NDK39: `exec/execbase.h`, `proto/exec.h` — CacheControl, CacheClearE
|
||||
- ADCD 2.1: `Libraries_Manual_guide/` — exec CacheControl autodoc
|
||||
- Commodore A3000/A4000 Technical Reference Manuals
|
||||
97
01_hardware/aga_a1200_a4000/gayle_ide_a1200.md
Normal file
97
01_hardware/aga_a1200_a4000/gayle_ide_a1200.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [AGA](README.md)
|
||||
|
||||
# Gayle — A1200 IDE & PCMCIA
|
||||
|
||||
## Overview
|
||||
|
||||
The A1200 uses a different revision of **Gayle** than the A600. The A1200 Gayle integrates:
|
||||
- **ATA/IDE interface** (for one hard drive + optional CD-ROM)
|
||||
- **PCMCIA Type II** slot (for modems, network cards, RAM cards)
|
||||
- **Interrupt routing** for both IDE and PCMCIA events
|
||||
|
||||
The A1200 Gayle is at a different base address layout than the A600 Gayle, and the byte-lane mapping differs from the A4000 IDE interface.
|
||||
|
||||
## Gayle ID
|
||||
|
||||
Read the Gayle ID by toggling read access to the ID register:
|
||||
```c
|
||||
#define GAYLE_ID_A1200 0xDA8000 /* read 8 bits, shifts on each access */
|
||||
|
||||
volatile UBYTE *gayle_id = (UBYTE *)0xDA8000;
|
||||
UBYTE id_byte = *gayle_id; /* returns $D0 (A600) or $D1 (A1200) */
|
||||
```
|
||||
|
||||
## IDE Register Map (A1200)
|
||||
|
||||
The A1200 IDE registers are at `$DA0000`, but the byte lanes are **swapped** relative to standard AT/ATA convention — the 8-bit registers appear at odd byte offsets within each 4-byte window:
|
||||
|
||||
| A1200 Address | ATA Register | RW |
|
||||
|---|---|---|
|
||||
| $DA0000 | Data (16-bit) | RW |
|
||||
| $DA0005 | Error (R) / Features (W) | RW |
|
||||
| $DA0009 | Sector Count | RW |
|
||||
| $DA000D | Sector Number (LBA 7:0) | RW |
|
||||
| $DA0011 | Cylinder Low (LBA 15:8) | RW |
|
||||
| $DA0015 | Cylinder High (LBA 23:16) | RW |
|
||||
| $DA0019 | Drive/Head select (LBA 27:24) | RW |
|
||||
| $DA001D | Status (R) / Command (W) | RW |
|
||||
| $DA101D | Alternate Status (R) / Device Control (W) | RW |
|
||||
|
||||
> [!NOTE]
|
||||
> The odd byte offset is because Gayle maps ATA registers on the **odd byte lane** of the 16-bit Amiga bus. Accessing `$DA0000+1` is the first register, not `$DA0000`. Many IDE drivers compensate with an offset of +1 or use a byte-swapped struct.
|
||||
|
||||
## Gayle Interrupt Register
|
||||
|
||||
```
|
||||
$DA9000 GAYLE_INT_STATUS (read/write)
|
||||
$DA9004 GAYLE_INT_ENABLE
|
||||
```
|
||||
|
||||
```c
|
||||
#define GAYLE_IRQ_IDE (1<<7) /* IDE interrupt pending */
|
||||
#define GAYLE_IRQ_CARD (1<<6) /* PCMCIA interrupt */
|
||||
#define GAYLE_IRQ_BVD1 (1<<5)
|
||||
#define GAYLE_IRQ_BVD2 (1<<4)
|
||||
#define GAYLE_IRQ_WP (1<<3) /* PCMCIA write protect */
|
||||
#define GAYLE_IRQ_CD (1<<2) /* PCMCIA card detect */
|
||||
```
|
||||
|
||||
Gayle routes its interrupt to **CIA-A /FLG** pin → CIAA ICR `CIAICRF_FLG` → CPU IPL 6.
|
||||
|
||||
Interrupt service routine must:
|
||||
1. Check `GAYLE_INT_STATUS` to identify source (IDE or PCMCIA)
|
||||
2. Clear the relevant bit by writing 0 to it
|
||||
3. If IDE: read the ATA status register to clear the IDE INTRQ
|
||||
|
||||
## PCMCIA Interface (A1200)
|
||||
|
||||
The A1200 PCMCIA slot is at:
|
||||
|
||||
| Address | Content |
|
||||
|---|---|
|
||||
| $600000–$9FFFFF | PCMCIA attribute memory (card CIS) |
|
||||
| $A00000–$A3FFFF | PCMCIA common memory (data) |
|
||||
|
||||
**Card detect sequence:**
|
||||
1. A card insertion triggers `GAYLE_IRQ_CD` (bit 2)
|
||||
2. Software reads CIS from attribute memory at $600000 to identify card type
|
||||
3. For ATA cards: configure card mode via PCMCIA CIS `CONFIG` tuple
|
||||
4. For network/modem cards: use the card's documented I/O mapping
|
||||
|
||||
## AmigaOS IDE Access
|
||||
|
||||
AmigaOS 3.1 includes `ata.device` (sometimes called `ide.device`) which drives the A1200 Gayle IDE internally. Applications never access Gayle registers directly — they go through dos.library → filesystem handler → ata.device.
|
||||
|
||||
```c
|
||||
/* Standard path — no direct Gayle access needed: */
|
||||
BPTR fh = Open("DH0:myfile", MODE_NEWFILE);
|
||||
Write(fh, data, length);
|
||||
Close(fh);
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- Commodore A1200 Technical Reference Manual — Gayle chapter (local archive)
|
||||
- NDK39: (no official Gayle header — community documented)
|
||||
- Amiga Hardware Reference (community supplement) — Gayle register map
|
||||
- `scsi.device` / `ata.device` Autodocs on ADCD 2.1
|
||||
109
01_hardware/common/address_space.md
Normal file
109
01_hardware/common/address_space.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md)
|
||||
|
||||
# Amiga Address Space
|
||||
|
||||
## Overview
|
||||
|
||||
The Amiga uses a **24-bit physical address bus** on OCS/ECS machines (68000/68020 effective), giving 16 MB of addressable space. AGA machines with 68030/040 and 32-bit-clean software can address the full 4 GB, but Chip RAM and custom registers remain in the lower 16 MB.
|
||||
|
||||
## Memory Map — 24-bit (OCS/ECS, A500/A600/A3000)
|
||||
|
||||
```
|
||||
$000000–$1FFFFF Chip RAM (max 2 MB on ECS, 512 KB on OCS A500)
|
||||
$200000–$9FFFFF Fast RAM (expansion via Zorro II autoconfig)
|
||||
$A00000–$BEFFFF Zorro II I/O space
|
||||
$BFD000–$BFDFFF CIA-B (8520, keyboard, floppy motor, disk side)
|
||||
$BFE001–$BFE1FF CIA-A (8520, parallel port, serial flags, timer)
|
||||
$C00000–$C7FFFF Slow RAM ("Ranger", DMA-visible but not fast)
|
||||
$C80000–$CFFFFF Zorro II expansion I/O (boards)
|
||||
$D00000–$D7FFFF Zorro II expansion I/O
|
||||
$D80000–$DBFFFF Reserved / board-specific
|
||||
$DC0000–$DCFFFF Real-Time Clock (MSM6242B / RF5C01A)
|
||||
$DD0000–$DEFFFF Reserved
|
||||
$DF0000–$DFFFFF Custom chip registers ($DFF000–$DFF1FE)
|
||||
$E00000–$E7FFFF Kick memory (WCS / Ranger slow RAM mirror)
|
||||
$E80000–$EFFFFF Autoconfig space (Zorro II probe)
|
||||
$F00000–$F7FFFF Extended Kickstart ROM (OS 3.1: second 256 KB)
|
||||
$F80000–$FFFFFF Kickstart ROM (512 KB mirror at top of 16 MB)
|
||||
```
|
||||
|
||||
## Memory Map — 32-bit (AGA, A1200/A4000)
|
||||
|
||||
```
|
||||
$000000–$1FFFFF 2 MB Chip RAM
|
||||
$200000–$07FFFFFF Fast RAM (on-board: 4–16 MB via Ramsey on A4000)
|
||||
Trapdoor/PCMCIA on A1200
|
||||
$A00000–$BEFFFF Zorro II I/O
|
||||
$BFD000 CIA-B
|
||||
$BFE001 CIA-A
|
||||
$C00000–$CFFFFF Slow RAM / board I/O
|
||||
$D80000–$D8FFFF IDE / Gayle (A1200/A4000)
|
||||
$DA0000–$DA3FFF PCMCIA attribute memory (A1200)
|
||||
$DC0000 RTC
|
||||
$DFF000–$DFFFFF Custom registers
|
||||
$E00000–$E7FFFF Kick mirror / WCS
|
||||
$F00000–$F7FFFF Extended ROM
|
||||
$F80000–$FFFFFF Kickstart ROM (512 KB)
|
||||
$01000000+ Zorro III expansion (32-bit, A3000/A4000 only)
|
||||
```
|
||||
|
||||
## Memory Type Classification
|
||||
|
||||
AmigaOS classifies memory by access flags used in `AllocMem()`:
|
||||
|
||||
| MEMF Flag | Value | Description |
|
||||
|---|---|---|
|
||||
| `MEMF_ANY` | 0 | No constraint |
|
||||
| `MEMF_PUBLIC` | 1<<0 | Accessible to all tasks and DMA |
|
||||
| `MEMF_CHIP` | 1<<1 | Chip RAM — accessible to custom chips (DMA) |
|
||||
| `MEMF_FAST` | 1<<2 | Fast RAM — CPU-only, no DMA, faster |
|
||||
| `MEMF_LOCAL` | 1<<8 | Not mapped out (always present) |
|
||||
| `MEMF_24BITDMA` | 1<<9 | Addressable within 24-bit space |
|
||||
| `MEMF_CLEAR` | 1<<16 | Zero-fill before returning |
|
||||
| `MEMF_REVERSE` | 1<<17 | Allocate from top of memory |
|
||||
| `MEMF_LARGEST` | 1<<18 | Return size of largest free block |
|
||||
| `MEMF_TOTAL` | 1<<19 | Return total memory of type |
|
||||
|
||||
### Chip RAM Requirement
|
||||
|
||||
Custom chip DMA can only access **Chip RAM** (`MEMF_CHIP`). This means:
|
||||
- Graphics bitmaps rendered by Blitter/Copper must be in Chip RAM
|
||||
- Audio sample data must be in Chip RAM
|
||||
- Copper lists must be in Chip RAM
|
||||
- Sprite data must be in Chip RAM
|
||||
|
||||
Fast RAM is **CPU-only** — generally used for code, non-DMA data structures, and stacks.
|
||||
|
||||
## Diagram
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
block:chip["Chip RAM\n$000000–$1FFFFF\n(DMA accessible)"]
|
||||
block:fast["Fast RAM\n$200000–$9FFFFF\n(CPU only, faster)"]
|
||||
block:zio["Zorro II I/O\n$A00000–$BEFFFF"]
|
||||
block:cia["CIA-A/B\n$BFD000/$BFE001"]
|
||||
block:slow["Slow/Ranger RAM\n$C00000–$C7FFFF"]
|
||||
block:rtc["RTC $DC0000"]
|
||||
block:custom["Custom Registers\n$DFF000–$DFFFFF"]
|
||||
block:rom["Kickstart ROM\n$F80000–$FFFFFF"]
|
||||
```
|
||||
|
||||
## Key Chip RAM Addresses
|
||||
|
||||
| Address | Content |
|
||||
|---|---|
|
||||
| $000000–$000400 | Exception vector table (copied from ROM) |
|
||||
| $000004 | `SysBase` pointer (exec library base) |
|
||||
| $000100 | Copper list scratch area (boot) |
|
||||
| $000400–$001000 | Reserved by OS |
|
||||
| $001000+ | Free Chip RAM (AvailMem result) |
|
||||
|
||||
> [!WARNING]
|
||||
> Writing to $000000–$000400 corrupts the exception table. Writing to $000004 corrupts `SysBase`. These addresses must never be allocated by user code; exec reserves them.
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `exec/memory.h` — MEMF_ flag definitions
|
||||
- ADCD 2.1 Hardware Manual: memory map chapter
|
||||
- Commodore A1200/A4000 Technical Reference Manuals (local archive)
|
||||
152
01_hardware/common/cia_chips.md
Normal file
152
01_hardware/common/cia_chips.md
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md)
|
||||
|
||||
# CIA Chips — 8520 MOS Technology
|
||||
|
||||
## Overview
|
||||
|
||||
The Amiga uses **two MOS 8520 CIA** (Complex Interface Adapter) chips, providing timers, parallel/serial I/O ports, a time-of-day clock, and interrupt generation. They are the primary source of hardware timing outside the vertical blank and audio DMA.
|
||||
|
||||
- **CIA-A** at `$BFE001` (even byte addresses)
|
||||
- **CIA-B** at `$BFD000` (odd byte addresses)
|
||||
|
||||
Both CIAs are accessed via byte reads/writes; the 68000 byte-lane placement means CIA-A uses even offsets and CIA-B uses odd offsets on the 16-bit bus.
|
||||
|
||||
## Register Map
|
||||
|
||||
Each CIA has 16 registers, spaced 256 bytes apart in the Amiga address space:
|
||||
|
||||
| Offset | Register | CIA-A Function | CIA-B Function |
|
||||
|---|---|---|---|
|
||||
| $000 | PRA | Parallel port data (input) | Disk control outputs |
|
||||
| $100 | PRB | Parallel port data (output) | Disk status inputs |
|
||||
| $200 | DDRA | Port A direction (1=output) | Port A direction |
|
||||
| $300 | DDRB | Port B direction | Port B direction |
|
||||
| $400 | TALO | Timer A low byte | Timer A low byte |
|
||||
| $500 | TAHI | Timer A high byte | Timer A high byte |
|
||||
| $600 | TBLO | Timer B low byte | Timer B low byte |
|
||||
| $700 | TBHI | Timer B high byte | Timer B high byte |
|
||||
| $800 | TODLO | TOD clock low (1/60 s) | Disk position (latched) |
|
||||
| $900 | TODMID | TOD clock mid | |
|
||||
| $A00 | TODHI | TOD clock high | |
|
||||
| $B00 | (unused) | — | — |
|
||||
| $C00 | SDR | Serial data register | Serial data register |
|
||||
| $D00 | ICR | Interrupt control | Interrupt control |
|
||||
| $E00 | CRA | Control register A | Control register A |
|
||||
| $F00 | CRB | Control register B | Control register B |
|
||||
|
||||
## CIA-A: $BFE001
|
||||
|
||||
CIA-A handles:
|
||||
|
||||
| Bit | Port A (PRA, read $BFE001) |
|
||||
|---|---|
|
||||
| 7 | `/FIR1` — joystick port 1 button |
|
||||
| 6 | `/FIR0` — joystick port 0 button |
|
||||
| 5 | `/RDY` — floppy ready |
|
||||
| 4 | `/TK0` — track 0 sensor |
|
||||
| 3 | `/WPRO` — write-protect |
|
||||
| 2 | `/CHNG` — disk change |
|
||||
| 1 | `/LED` — power LED (write: 0=bright) |
|
||||
| 0 | `/OVL` — Chip RAM overlay (write during boot) |
|
||||
|
||||
Port B (PRB, $BFE101): Parallel port data lines D0–D7.
|
||||
|
||||
**CIA-A interrupts** appear on **CPU IPL level 2** via INTENA bit `INTB_EXTER` — actually CIA is on IPL 6.
|
||||
|
||||
## CIA-B: $BFD000
|
||||
|
||||
CIA-B handles floppy drive motor/selection and disk DMA sync:
|
||||
|
||||
| Bit | Port A (PRA, $BFD000) |
|
||||
|---|---|
|
||||
| 7 | `/MTR` — motor on/off |
|
||||
| 6 | `/SEL3` — drive 3 select |
|
||||
| 5 | `/SEL2` — drive 2 select |
|
||||
| 4 | `/SEL1` — drive 1 select |
|
||||
| 3 | `/SEL0` — drive 0 select |
|
||||
| 2 | `/SIDE` — head side (0=upper) |
|
||||
| 1 | `/DIR` — step direction |
|
||||
| 0 | `/STEP` — step pulse |
|
||||
|
||||
Port B (PRB, $BFD100): Parallel port shadow (less commonly used on B).
|
||||
|
||||
**CIA-B interrupts** appear on **CPU IPL level 6**.
|
||||
|
||||
## Timers
|
||||
|
||||
Each CIA has two 16-bit countdown timers (Timer A and Timer B):
|
||||
|
||||
- Count from a loaded latch value down to zero
|
||||
- Can be one-shot or continuous
|
||||
- Clock sources: system clock (709 kHz PAL / 715 kHz NTSC), or Timer A output (for Timer B)
|
||||
- Timer A can generate `SDR` baud rate for serial output
|
||||
|
||||
**Control Register A (CRA) bits:**
|
||||
```
|
||||
bit 0: START — 1 = timer running
|
||||
bit 1: PBON — 1 = timer output on Port B bit 6
|
||||
bit 2: OUTMODE — 0=pulse, 1=toggle
|
||||
bit 3: RUNMODE — 0=continuous, 1=one-shot
|
||||
bit 4: LOAD — 1 = force load latch into counter
|
||||
bit 5: INMODE — 0=clock, 1=count rising edges on CNT pin
|
||||
bit 6: SPMODE — 0=SDR input, 1=SDR output
|
||||
bit 7: TODIN — 0=60 Hz TOD, 1=50 Hz TOD (PAL)
|
||||
```
|
||||
|
||||
## Time-of-Day (TOD) Clock
|
||||
|
||||
24-bit counter, clocked at 60 Hz (NTSC) or 50 Hz (PAL):
|
||||
|
||||
- CIA-A TOD: used by OS as software clock
|
||||
- TOD registers latch on read of TODHI — must read TODHI first, then TODMID, then TODLO
|
||||
- `ciaa.ciatodhi` → `ciaa.ciatodmid` → `ciaa.ciatodlo`
|
||||
- Set by writing TODHI → TODMID → TODLO (halts during write)
|
||||
|
||||
## Interrupt Control Register (ICR)
|
||||
|
||||
Write to enable interrupts, read to see which fired:
|
||||
|
||||
```c
|
||||
/* Enable Timer A interrupt */
|
||||
ciaa.ciaicr = CIAICRF_SETCLR | CIAICRF_TA;
|
||||
|
||||
/* On read: bits indicate which sources fired */
|
||||
UBYTE icr = ciaa.ciaicr;
|
||||
if (icr & CIAICRF_TA) { /* Timer A fired */ }
|
||||
if (icr & CIAICRF_TB) { /* Timer B fired */ }
|
||||
if (icr & CIAICRF_ALRM) { /* TOD alarm fired */ }
|
||||
if (icr & CIAICRF_SP) { /* Serial register full/empty */ }
|
||||
if (icr & CIAICRF_FLG) { /* /FLAG pin (index pulse on CIA-B) */ }
|
||||
```
|
||||
|
||||
Write bit 7 (`CIAICRF_SETCLR`): 1 = set enable bits, 0 = clear enable bits.
|
||||
|
||||
## AmigaOS Timer Device Integration
|
||||
|
||||
AmigaOS's `timer.device` uses CIA timers internally:
|
||||
- `UNIT_MICROHZ` — uses CIA-A Timer A for microsecond delays
|
||||
- `UNIT_VBLANK` — uses vertical blank interrupt (not CIA)
|
||||
- `UNIT_ECLOCK` — uses the E clock (709/715 kHz, same as CIA clock)
|
||||
|
||||
Direct CIA programming should be done with `ciaa`/`ciab` resource claims via `OpenResource("ciaa.resource")` — not by poking CIA registers directly.
|
||||
|
||||
## C Access via NDK Headers
|
||||
|
||||
```c
|
||||
#include <hardware/cia.h>
|
||||
#include <resources/cia.h>
|
||||
|
||||
/* CIA-A is at fixed address */
|
||||
#define ciaa (*((volatile struct CIA *)0xBFE001))
|
||||
#define ciab (*((volatile struct CIA *)0xBFD000))
|
||||
|
||||
/* struct CIA fields (hardware/cia.h): */
|
||||
/* ciaa.ciapra, ciaa.ciaprb, ciaa.ciaicr, ciaa.ciacra, ... */
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- MOS Technology 6526/8520 datasheet
|
||||
- ADCD 2.1 Hardware Manual — CIA chapter: http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/
|
||||
- NDK39: `hardware/cia.h`, `resources/cia.h`
|
||||
- Autodocs: `cia` resource — http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node00C7.html
|
||||
141
01_hardware/common/m68k_cpu.md
Normal file
141
01_hardware/common/m68k_cpu.md
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md)
|
||||
|
||||
# M68k CPU on the Amiga
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaOS runs on the Motorola 68000 family exclusively. The CPU operates in two privilege modes and interacts with the custom chips via the shared 16/32-bit bus arbitrated by Agnus/Alice.
|
||||
|
||||
## Privilege Modes
|
||||
|
||||
| Mode | SR[13] (S-bit) | Stack Pointer | Access |
|
||||
|---|---|---|---|
|
||||
| **Supervisor** | 1 | SSP (A7') | Full hardware access |
|
||||
| **User** | 0 | USP (A7) | Restricted — no privileged instructions |
|
||||
|
||||
AmigaOS runs entirely in **supervisor mode**. User-mode tasks switch to supervisor via `Supervisor()` or trap instructions. The OS does not enforce user-mode isolation — all tasks share one address space.
|
||||
|
||||
## Register Set
|
||||
|
||||
```
|
||||
D0–D7 Data registers (32-bit)
|
||||
A0–A6 Address registers (32-bit)
|
||||
A7 Stack pointer (USP in user mode, SSP in supervisor mode)
|
||||
PC Program counter
|
||||
SR Status register (CCR + supervisor bits)
|
||||
```
|
||||
|
||||
**CCR (Condition Code Register) — lower byte of SR:**
|
||||
```
|
||||
bit 4: X (extend)
|
||||
bit 3: N (negative)
|
||||
bit 2: Z (zero)
|
||||
bit 1: V (overflow)
|
||||
bit 0: C (carry)
|
||||
```
|
||||
|
||||
**SR upper byte (supervisor only):**
|
||||
```
|
||||
bit 15: T1 (trace mode — single-step)
|
||||
bit 14: T0
|
||||
bit 13: S (supervisor state)
|
||||
bit 10-8: I2-I0 (interrupt mask level, 0–7)
|
||||
```
|
||||
|
||||
## Exception Vector Table
|
||||
|
||||
Located at **$000000** (physical), shadowed from Kick ROM into Chip RAM on boot.
|
||||
|
||||
| Offset | Vector | Description |
|
||||
|---|---|---|
|
||||
| $000 | Reset SSP | Initial supervisor stack pointer |
|
||||
| $004 | Reset PC | Initial program counter (ROM entry) |
|
||||
| $008 | Bus Error | Access fault |
|
||||
| $00C | Address Error | Odd-address word/long access |
|
||||
| $010 | Illegal Instruction | Undefined opcode |
|
||||
| $014 | Divide by Zero | DIVS/DIVU by zero |
|
||||
| $018 | CHK | CHK instruction bound check fail |
|
||||
| $01C | TRAPV / cpTRAPcc | Overflow trap |
|
||||
| $020 | Privilege Violation | User-mode privileged instruction |
|
||||
| $024 | Trace | Single-step trap |
|
||||
| $028 | Line 1010 (A-line) | Opcode $Axxx — OS trap dispatch |
|
||||
| $02C | Line 1111 (F-line) | Opcode $Fxxx — FPU / emulation |
|
||||
| $060 | Spurious Interrupt | No response to interrupt acknowledge |
|
||||
| $064 | Level 1 Autovector | CIA-B timer / serial / disk |
|
||||
| $068 | Level 2 Autovector | CIA-A, software |
|
||||
| $06C | Level 3 Autovector | VBL, copper, blitter |
|
||||
| $070 | Level 4 Autovector | Audio, disk DMA |
|
||||
| $074 | Level 5 Autovector | Serial port |
|
||||
| $078 | Level 6 Autovector | CIA / ext interrupt |
|
||||
| $07C | Level 7 Autovector | NMI (not maskable) |
|
||||
| $080–$0BC | TRAP #0–#15 | Software traps |
|
||||
|
||||
## AmigaOS Use of Exception Vectors
|
||||
|
||||
- **A-Line ($028):** AmigaOS uses this for its internal library call dispatch on some early titles; modern code uses direct JSR via library base.
|
||||
- **Level 3 ($06C):** Vertical Blank interrupt — exec's `AddIntServer(INTB_VERTB, ...)` chains here.
|
||||
- **Level 6 ($078):** CIA interrupts chain here; exec dispatches to `INTB_EXTER` servers.
|
||||
- **TRAP #0 ($080):** Used by `Supervisor()` to enter supervisor mode from user code.
|
||||
|
||||
## Interrupt Priority Levels
|
||||
|
||||
AmigaOS maps hardware interrupt levels to internal interrupt bits (`INTENA`/`INTREQ`):
|
||||
|
||||
| IPL | Source | INTENA bits |
|
||||
|---|---|---|
|
||||
| 1 | Serial TX, disk block | `INTB_TBE`, `INTB_DSKBLK` |
|
||||
| 2 | Software (PostIntServer) | `INTB_SOFTINT` |
|
||||
| 3 | VBlank, copper, blitter | `INTB_VERTB`, `INTB_COPPER`, `INTB_BLIT` |
|
||||
| 4 | Audio ch 0–3, disk DMA | `INTB_AUD0`–`INTB_AUD3`, `INTB_DSKSYNC` |
|
||||
| 5 | Serial RX | `INTB_RBF` |
|
||||
| 6 | External / CIA | `INTB_EXTER` |
|
||||
| 7 | NMI (rarely used) | — |
|
||||
|
||||
## CPU Detection at Runtime
|
||||
|
||||
AmigaOS stores CPU capability flags in `ExecBase->AttnFlags` (offset $128):
|
||||
|
||||
```c
|
||||
#include <exec/execbase.h>
|
||||
|
||||
struct ExecBase *SysBase = *((struct ExecBase **)4);
|
||||
UWORD attn = SysBase->AttnFlags;
|
||||
|
||||
if (attn & AFF_68020) { /* 68020+ present */ }
|
||||
if (attn & AFF_68030) { /* 68030+ present */ }
|
||||
if (attn & AFF_68040) { /* 68040+ present */ }
|
||||
if (attn & AFF_68060) { /* 68060 present */ }
|
||||
if (attn & AFF_FPU) { /* FPU present */ }
|
||||
if (attn & AFF_68881) { /* 68881/68882 */ }
|
||||
```
|
||||
|
||||
**AttnFlags bit definitions** (`exec/execbase.h`):
|
||||
```c
|
||||
#define AFF_68010 (1<<0)
|
||||
#define AFF_68020 (1<<1)
|
||||
#define AFF_68030 (1<<2)
|
||||
#define AFF_68040 (1<<3)
|
||||
#define AFF_68881 (1<<4) /* on-chip FPU or external 68881 */
|
||||
#define AFF_FPU (1<<4)
|
||||
#define AFF_68882 (1<<5)
|
||||
#define AFF_FPU40 (1<<6) /* 040/060 on-chip FPU */
|
||||
#define AFF_68060 (1<<7)
|
||||
```
|
||||
|
||||
## Key Instruction Subsets by CPU
|
||||
|
||||
| Instruction | 68000 | 68020 | 68030 | 68040 |
|
||||
|---|---|---|---|---|
|
||||
| MULS/MULU 16×16 | ✓ | ✓ | ✓ | ✓ |
|
||||
| MULS/MULU 32×32 | ✗ | ✓ | ✓ | ✓ |
|
||||
| Bit-field (BFEXTU etc.) | ✗ | ✓ | ✓ | ✓ |
|
||||
| CALLM/RTM | ✗ | ✓ | ✗ | ✗ |
|
||||
| CAS/CAS2 | ✗ | ✓ | ✓ | ✓ |
|
||||
| LPSTOP | ✗ | ✗ | ✓ | ✓ |
|
||||
| CINV/CPUSH | ✗ | ✗ | ✓ | ✓ |
|
||||
|
||||
## References
|
||||
|
||||
- Motorola *M68000 Family Programmer's Reference Manual* (M68000PM/AD)
|
||||
- ADCD 2.1 Hardware Manual: http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node0000.html
|
||||
- NDK39: `exec/execbase.h` — `AttnFlags` definitions
|
||||
139
01_hardware/common/zorro_bus.md
Normal file
139
01_hardware/common/zorro_bus.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md)
|
||||
|
||||
# Zorro Bus — Expansion Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
The Amiga uses the **Zorro** expansion bus for add-on cards. There are two generations:
|
||||
|
||||
- **Zorro II** — 16-bit, 24-bit addressing, 7 MHz, compatible with A2000/A3000/A4000
|
||||
- **Zorro III** — 32-bit, 32-bit addressing, up to 33 MHz burst, A3000/A4000 only
|
||||
|
||||
Zorro uses **AutoConfig** — a standardised plug-and-play configuration protocol that predates PCI by several years.
|
||||
|
||||
## Zorro II
|
||||
|
||||
| Parameter | Value |
|
||||
|---|---|
|
||||
| Data bus | 16-bit |
|
||||
| Address bus | 24-bit |
|
||||
| Clock | 7.14 MHz (bus cycle ≈ 280 ns) |
|
||||
| Max transfer | ~5 MB/s (DMA) |
|
||||
| Address space | $A00000–$EFFFFF (I/O), $200000–$9FFFFF (RAM) |
|
||||
| Slots | 5 (A2000), 3 (A3000) |
|
||||
|
||||
Zorro II cards appear in the 16 MB address space. RAM cards are configured into $200000–$9FFFFF. I/O cards use $A00000–$DEFFFF.
|
||||
|
||||
## Zorro III
|
||||
|
||||
| Parameter | Value |
|
||||
|---|---|
|
||||
| Data bus | 32-bit |
|
||||
| Address bus | 32-bit |
|
||||
| Clock | Up to 33 MHz burst |
|
||||
| Max transfer | ~40 MB/s (DMA) |
|
||||
| Address space | $01000000 and above |
|
||||
| Slots | 4 (A3000), 5 (A4000) |
|
||||
|
||||
Zorro III extends into the 32-bit address space, allowing large RAM cards (32–128 MB) and fast peripherals. Requires a 32-bit CPU (68030+) and OS support.
|
||||
|
||||
## AutoConfig Protocol
|
||||
|
||||
AutoConfig allows the OS to discover and configure cards without jumpers:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant OS as AmigaOS (expansion.library)
|
||||
participant Card as Zorro Card
|
||||
|
||||
OS->>Card: Read $E80000 (config space)
|
||||
Card-->>OS: Manufacturer ID (16-bit)
|
||||
OS->>Card: Read $E80002
|
||||
Card-->>OS: Product ID, flags
|
||||
OS->>Card: Read board size, type
|
||||
OS->>OS: AllocAbs() / ConfigBoard()
|
||||
OS->>Card: Write base address
|
||||
Card-->>OS: Card configured, moves off $E80000
|
||||
```
|
||||
|
||||
**Key AutoConfig registers** (read from $E80000–$E8007F before configuration):
|
||||
|
||||
| Offset | Content |
|
||||
|---|---|
|
||||
| $00 | er_Type (board type: RAM/IO, Zorro II/III) |
|
||||
| $02 | er_Product (product ID) |
|
||||
| $04 | er_Flags |
|
||||
| $06 | er_Reserved03 |
|
||||
| $08–$0A | er_Manufacturer (16-bit) |
|
||||
| $0C–$0F | er_SerialNumber |
|
||||
| $10–$11 | er_InitDiagVec (diagnostic ROM vector) |
|
||||
|
||||
**Board types** (`er_Type` bits):
|
||||
```c
|
||||
#define ERT_TYPEMASK 0xC0
|
||||
#define ERT_ZORROII 0xC0 /* Zorro II card */
|
||||
#define ERT_ZORROIII 0x80 /* Zorro III card */
|
||||
#define ERTB_MEMLIST 5 /* board is RAM, add to free list */
|
||||
#define ERTB_DIAGVALID 4 /* DiagArea ROM is valid */
|
||||
#define ERTB_CHAINEDCONFIG 3 /* more boards to configure */
|
||||
```
|
||||
|
||||
## expansion.library
|
||||
|
||||
AmigaOS provides `expansion.library` to manage Zorro configuration:
|
||||
|
||||
```c
|
||||
#include <libraries/expansion.h>
|
||||
#include <clib/expansion_protos.h>
|
||||
|
||||
/* Find a configured board by manufacturer/product */
|
||||
struct ConfigDev *cd = NULL;
|
||||
while ((cd = FindConfigDev(cd, MANUF_ID, PROD_ID)) != NULL) {
|
||||
APTR base = cd->cd_BoardAddr;
|
||||
ULONG size = cd->cd_BoardSize;
|
||||
/* use board at base */
|
||||
}
|
||||
```
|
||||
|
||||
**Key structures:**
|
||||
```c
|
||||
struct ConfigDev {
|
||||
struct Node cd_Node;
|
||||
UBYTE cd_Flags;
|
||||
UBYTE cd_Pad;
|
||||
struct ExpansionRom cd_Rom; /* copy of autoconfig ROM area */
|
||||
APTR cd_BoardAddr; /* configured base address */
|
||||
ULONG cd_BoardSize;
|
||||
UWORD cd_SlotAddr;
|
||||
UWORD cd_SlotSize;
|
||||
APTR cd_Driver;
|
||||
struct ConfigDev *cd_NextCD;
|
||||
ULONG cd_Unused[4];
|
||||
};
|
||||
```
|
||||
|
||||
## DiagArea — Card ROM
|
||||
|
||||
Cards with `ERTB_DIAGVALID` have a small ROM (DiagArea) that the OS calls during boot:
|
||||
|
||||
```c
|
||||
struct DiagArea {
|
||||
UBYTE da_Config; /* flags */
|
||||
UBYTE da_Flags;
|
||||
UWORD da_Size;
|
||||
UWORD da_DiagPoint; /* offset to diagnostic code */
|
||||
UWORD da_BootPoint; /* offset to boot code */
|
||||
UWORD da_Name; /* offset to name string */
|
||||
UWORD da_Reserved01;
|
||||
UWORD da_Reserved02;
|
||||
};
|
||||
```
|
||||
|
||||
The boot vector is called by `ConfigChain()` during the early boot sequence — this is how SCSI controllers install their filesystem handlers.
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `libraries/expansion.h`, `libraries/configregs.h`, `libraries/configvars.h`
|
||||
- ADCD 2.1 Autodocs: `expansion` — http://amigadev.elowar.com/read/ADCD_2.1/Includes_and_Autodocs_3._guide/node025B.html
|
||||
- *Amiga Hardware Reference Manual* 3rd ed. — AutoConfig chapter
|
||||
- Dave Haynie's Zorro III specification documents
|
||||
67
01_hardware/ecs_a600_a3000/README.md
Normal file
67
01_hardware/ecs_a600_a3000/README.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md)
|
||||
|
||||
# ECS Chipset — A600 / A3000 / A500+
|
||||
|
||||
## Overview
|
||||
|
||||
The **Enhanced Chip Set** (ECS) is a significant revision of OCS, shipping from 1990 onward. It adds 2 MB Chip RAM addressing, programmable display timing, and extended registers while maintaining full backward compatibility with OCS software.
|
||||
|
||||
## Chip Summary
|
||||
|
||||
| Chip | Part | Changes from OCS |
|
||||
|---|---|---|
|
||||
| **Super Agnus** | MOS 8372A | Addresses 2 MB Chip RAM, extended DMA window |
|
||||
| **ECS Denise** | MOS 8373 | BPLCON3, border blank, programmable sync |
|
||||
| **Paula** | MOS 8364 | Unchanged |
|
||||
|
||||
## Contents
|
||||
|
||||
| File | Topic |
|
||||
|---|---|
|
||||
| [chipset_ecs.md](chipset_ecs.md) | Super Agnus and ECS Denise internals |
|
||||
| [ecs_registers_delta.md](ecs_registers_delta.md) | New/changed registers vs OCS |
|
||||
| [productivity_modes.md](productivity_modes.md) | Multiscan/productivity display modes |
|
||||
| [gary_gayle.md](gary_gayle.md) | Gary (A3000) and Gayle (A600) chips: IDE, PCMCIA |
|
||||
| [chip_ram_expansion.md](chip_ram_expansion.md) | 2 MB Chip RAM with Super Agnus |
|
||||
|
||||
## ECS vs OCS — Key Differences
|
||||
|
||||
| Feature | OCS | ECS |
|
||||
|---|---|---|
|
||||
| Max Chip RAM | 1 MB (Fat Agnus) | **2 MB** (Super Agnus) |
|
||||
| Display sync | Fixed NTSC/PAL | **BEAMCON0** — programmable |
|
||||
| Bitplane scroll | 4-bit (BPLCON1) | Extended (ECS Denise) |
|
||||
| Border blank | No | **BPLCON3** border control |
|
||||
| Hires sprites | No | ECS Denise extended sprite control |
|
||||
| DMA window | Smaller | Extended: wider bitplane fetch |
|
||||
|
||||
## Identifying ECS at Runtime
|
||||
|
||||
```c
|
||||
#include <exec/execbase.h>
|
||||
|
||||
struct ExecBase *SysBase = *((struct ExecBase **)4);
|
||||
/* AttnFlags does not directly identify chipset */
|
||||
|
||||
/* Use graphics.library GfxBase->ChipRevBits0 */
|
||||
#include <graphics/gfxbase.h>
|
||||
struct GfxBase *GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
|
||||
if (GfxBase->ChipRevBits0 & GFXB_BIG_BLITTER) { /* ECS+ */ }
|
||||
if (GfxBase->ChipRevBits0 & GFXB_HR_AGNUS) { /* Super Agnus */ }
|
||||
if (GfxBase->ChipRevBits0 & GFXB_HR_DENISE) { /* ECS Denise */ }
|
||||
```
|
||||
|
||||
## Machines Using ECS
|
||||
|
||||
| Model | Notes |
|
||||
|---|---|
|
||||
| A3000 | Super Agnus + ECS Denise; 68030; SCSI; Zorro III |
|
||||
| A500+ | Super Agnus (1 MB variant); ECS Denise; no IDE |
|
||||
| A600 | Super Agnus (1 MB variant); ECS Denise; Gayle; IDE; PCMCIA |
|
||||
| A2000 (late) | Some late rev boards shipped with ECS chips |
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — ECS extension chapters
|
||||
- NDK39: `graphics/gfxbase.h` — ChipRevBits0 flags
|
||||
- *Amiga Hardware Reference Manual* 3rd ed. — ECS appendix
|
||||
76
01_hardware/ecs_a600_a3000/chip_ram_expansion.md
Normal file
76
01_hardware/ecs_a600_a3000/chip_ram_expansion.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [ECS](README.md)
|
||||
|
||||
# 2 MB Chip RAM with Super Agnus
|
||||
|
||||
## Overview
|
||||
|
||||
The original Agnus (8361/8367) could address only **512 KB** of Chip RAM. The Fat Agnus (later OCS revision) addressed **1 MB**. Super Agnus (8372A) extends the DMA address bus to **21 bits**, allowing **2 MB** of Chip RAM to be addressed by all DMA channels.
|
||||
|
||||
## Requirements for 2 MB Chip RAM
|
||||
|
||||
All of the following must be present:
|
||||
|
||||
1. **Super Agnus 8372A** — 2 MB variant (not all 8372A chips support 2 MB; check marking)
|
||||
2. **2 MB of Chip RAM physically installed** — requires modified A3000 or a third-party board
|
||||
3. **OS 2.0 or later** — earlier OS does not manage the extended Chip RAM
|
||||
|
||||
On the A3000, 2 MB Chip RAM is the standard configuration. On A500/A2000 with Super Agnus, it requires a RAM expansion that adds 1 MB in the Chip RAM window.
|
||||
|
||||
## Address Space Layout with 2 MB Chip RAM
|
||||
|
||||
```
|
||||
$000000–$1FFFFF 2 MB Chip RAM (DMA accessible by all channels)
|
||||
$200000+ Fast RAM (CPU only)
|
||||
```
|
||||
|
||||
The Chip RAM extends from $000000 to $1FFFFF. Previously, $100000–$1FFFFF was "ranger" slow RAM, not DMA-accessible.
|
||||
|
||||
## OS Detection and Use
|
||||
|
||||
AmigaOS automatically discovers Chip RAM size via the exec memory list:
|
||||
|
||||
```c
|
||||
/* Check available Chip RAM */
|
||||
ULONG chip_free = AvailMem(MEMF_CHIP);
|
||||
ULONG chip_total = AvailMem(MEMF_CHIP | MEMF_TOTAL);
|
||||
```
|
||||
|
||||
The exec memory list is built at boot time from the chip RAM size detected by the ROM initialisation code, which queries Agnus's internal address counter.
|
||||
|
||||
## AmigaOS ROM Initialisation (Exec init)
|
||||
|
||||
During cold boot, the Kickstart ROM probes Chip RAM size:
|
||||
|
||||
1. Write a test pattern to $100000 (top of 1 MB range)
|
||||
2. Read back — if the value matches, 2 MB Chip RAM is present
|
||||
3. The exec `MemHeader` for Chip RAM is extended to $1FFFFF
|
||||
|
||||
This is performed in the `RomBoot()` → `InitCode()` sequence before the exec memory system is fully initialised.
|
||||
|
||||
## Implications for Programming
|
||||
|
||||
- **Bitplane pointers** can address any location in the 2 MB range
|
||||
- **Copper lists, sprite data, audio samples** can all use the upper 1 MB
|
||||
- `AllocMem(size, MEMF_CHIP)` will draw from the full 2 MB pool
|
||||
- **MEMF_24BITDMA** is set on Chip RAM to indicate DMA accessibility within the 24-bit space
|
||||
|
||||
## Common Pitfall: 1 MB vs 2 MB Super Agnus
|
||||
|
||||
Some Super Agnus chips (8372A rev 1) are hardware-limited to 1 MB despite the ECS part number. Identifying the 2 MB variant:
|
||||
|
||||
```asm
|
||||
; Read the Agnus chip ID from VPOSR
|
||||
move.w $DFF004, d0 ; VPOSR
|
||||
and.w #$7F00, d0 ; mask to chip ID bits
|
||||
cmp.w #$2300, d0 ; 8372A 2MB = ID $23?
|
||||
beq .is_2mb_agnus
|
||||
```
|
||||
|
||||
Software should not assume 2 MB Chip RAM — always use `AvailMem()` to determine the actual size.
|
||||
|
||||
## References
|
||||
|
||||
- Commodore A3000 Technical Reference Manual — memory section
|
||||
- AmigaMail Vol. 2 — Chip RAM expansion articles
|
||||
- NDK39: `exec/memory.h` — MEMF flags
|
||||
- ADCD 2.1 Hardware Manual — memory map section
|
||||
119
01_hardware/ecs_a600_a3000/chipset_ecs.md
Normal file
119
01_hardware/ecs_a600_a3000/chipset_ecs.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [ECS](README.md)
|
||||
|
||||
# ECS Chipset Internals — Super Agnus & ECS Denise
|
||||
|
||||
## Super Agnus (MOS 8372A)
|
||||
|
||||
### Chip RAM Addressing
|
||||
|
||||
OCS Agnus could only generate 19-bit DMA addresses (512 KB) or 20-bit (1 MB with Fat Agnus). Super Agnus extends this to **21 bits**, addressing 2 MB of Chip RAM.
|
||||
|
||||
The revision of Super Agnus present determines the Chip RAM limit:
|
||||
|
||||
| Part | Chip RAM Max | Marking |
|
||||
|---|---|---|
|
||||
| 8372A rev 1 | 1 MB | AGNUS 8372A |
|
||||
| 8372A rev 4+ | 2 MB | AGNUS 8372A (2MB) |
|
||||
|
||||
> [!NOTE]
|
||||
> Software cannot assume 2 MB Chip RAM is available just because Super Agnus is present. The actual installed RAM amount must be checked via `AvailMem(MEMF_CHIP)`.
|
||||
|
||||
### Extended DMA Window
|
||||
|
||||
Super Agnus extends the bitplane DMA fetch window, allowing:
|
||||
- Full overscan displays without copper tricks
|
||||
- Access to the full 2 MB address range for all DMA channels
|
||||
|
||||
### AGNUS ID Register
|
||||
|
||||
Super Agnus provides an ID register readable via the `VPOSR` / `DIWSTRT` path. The chip revision can be read:
|
||||
|
||||
```asm
|
||||
move.w VPOSR+custom, d0 ; read VPOSR
|
||||
lsr.w #8, d0 ; shift to get Agnus ID in low byte
|
||||
```
|
||||
|
||||
| VPOSR[15:8] | Chip | Notes |
|
||||
|---|---|---|
|
||||
| $00 | OCS Agnus 8367/8361 | Original |
|
||||
| $10 | OCS Fat Agnus 8371 | 1 MB PAL |
|
||||
| $20 | Super Agnus 8372A | ECS, 1 or 2 MB |
|
||||
| $30 | Super Agnus 8372B | Some ECS |
|
||||
|
||||
---
|
||||
|
||||
## ECS Denise (MOS 8373)
|
||||
|
||||
### New Capabilities
|
||||
|
||||
ECS Denise adds to OCS Denise (8362):
|
||||
|
||||
1. **BPLCON3** — new control register for border colour, sprite bank
|
||||
2. **Sub-pixel scrolling** — additional scroll control bits
|
||||
3. **Genlock extensions** — improved external sync handling
|
||||
4. **Border blank** — BPLCON3 can blank the border area to colour 0
|
||||
|
||||
### DENISEID — Revision Register
|
||||
|
||||
ECS Denise provides a self-identification register at `$DFF07C` (read only on ECS+):
|
||||
|
||||
```asm
|
||||
move.w $DFF07C, d0 ; read DENISEID
|
||||
```
|
||||
|
||||
| Value | Chip |
|
||||
|---|---|
|
||||
| $FFFF | OCS Denise 8362 (register not present) |
|
||||
| $00FC | ECS Denise 8373 |
|
||||
| $00F8 | AGA Lisa |
|
||||
|
||||
---
|
||||
|
||||
## BPLCON3 — ECS Denise Extension
|
||||
|
||||
New register at `$DFF106` (ECS only, must not be written on OCS):
|
||||
|
||||
```
|
||||
bit 15-13: BANK2-0 — sprite colour bank (AGA: upper 4 bits of colour reg)
|
||||
bit 12-10: PF2OF2-0 — playfield 2 colour offset (for dual playfield)
|
||||
bit 9: LOCT — low colour enable (AGA HAM8 mode)
|
||||
bit 6: BRDRBLNK — border blank: forces border area to colour 0
|
||||
bit 5: BRDNTRAN — border not-transparent (disable border transparency)
|
||||
bit 4: ZDCLKEN — horizontal/vertical count display
|
||||
bit 3: BRDSPRT — sprites in border area enable
|
||||
bit 2: EXTBLKEN — external blank signal
|
||||
```
|
||||
|
||||
**Border blank use:**
|
||||
```asm
|
||||
move.w #$0020, $DFF106 ; set BRDRBLNK — blank border area
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GfxBase ChipRevBits0 Flags
|
||||
|
||||
```c
|
||||
/* graphics/gfxbase.h */
|
||||
#define GFXB_BIG_BLITTER 0 /* ECS big blitter present */
|
||||
#define GFXB_BLITTER_DMA 1
|
||||
#define GFXB_HR_AGNUS 2 /* Super Agnus */
|
||||
#define GFXB_HR_DENISE 3 /* ECS Denise */
|
||||
#define GFXB_AA_ALICE 4 /* AGA Alice */
|
||||
#define GFXB_AA_LISA 5 /* AGA Lisa */
|
||||
```
|
||||
|
||||
Reading chipset type in C:
|
||||
```c
|
||||
UBYTE rev = GfxBase->ChipRevBits0;
|
||||
BOOL is_ecs_agnus = (rev & (1 << GFXB_HR_AGNUS)) != 0;
|
||||
BOOL is_ecs_denise = (rev & (1 << GFXB_HR_DENISE)) != 0;
|
||||
BOOL is_aga = (rev & (1 << GFXB_AA_ALICE)) != 0;
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — ECS registers, Super Agnus chapter
|
||||
- NDK39: `graphics/gfxbase.h`
|
||||
- AmigaMail Vol. 2 — ECS chipset programming articles
|
||||
- *Amiga Hardware Reference Manual* 3rd ed. — Appendix F (ECS)
|
||||
114
01_hardware/ecs_a600_a3000/ecs_registers_delta.md
Normal file
114
01_hardware/ecs_a600_a3000/ecs_registers_delta.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [ECS](README.md)
|
||||
|
||||
# ECS Register Deltas vs OCS
|
||||
|
||||
This file documents registers that are **new or changed in ECS** versus OCS. OCS registers not listed here are unchanged.
|
||||
|
||||
## New Registers
|
||||
|
||||
### BEAMCON0 — $DFF1DC (ECS only)
|
||||
|
||||
The most significant new ECS register. Controls display sync generation and timing mode.
|
||||
|
||||
```
|
||||
bit 15: HARDDIS — disable hard limits on display window
|
||||
bit 14: LPENDIS — disable light pen latch
|
||||
bit 13: VARVBEN — enable variable VBlank
|
||||
bit 12: LOLDIS — disable long line sync
|
||||
bit 11: CSCBEN — composite sync on colour burst
|
||||
bit 10: VARVSYEN — variable vertical sync
|
||||
bit 9: VARHSYEN — variable horizontal sync
|
||||
bit 8: VARBEAMEN— variable beam enable
|
||||
bit 7: DUAL — dual sync (separate composite + RGB)
|
||||
bit 6: PAL — 1 = PAL timing, 0 = NTSC timing
|
||||
bit 5: VARCSYEN — variable composite sync
|
||||
bit 4: BLANKEN — enable blanking signal
|
||||
bit 3: CSYTRUE — composite sync polarity
|
||||
bit 2: VSYTRUE — vertical sync polarity
|
||||
bit 1: HSYTRUE — horizontal sync polarity
|
||||
bit 0: MONCSYEN — monochrome composite sync enable
|
||||
```
|
||||
|
||||
**Default OCS behaviour** is replicated by writing $0000 to BEAMCON0 on ECS.
|
||||
|
||||
**PAL/NTSC software switch:**
|
||||
```asm
|
||||
move.w #$0020, $DFF1DC ; BEAMCON0 = PAL mode
|
||||
move.w #$0000, $DFF1DC ; BEAMCON0 = NTSC mode
|
||||
```
|
||||
|
||||
**Productivity mode (31 kHz):**
|
||||
```asm
|
||||
move.w #$0A00, $DFF1DC ; VARBEAMEN + VARVSYEN (31 kHz VGA-like)
|
||||
```
|
||||
|
||||
### BPLCON3 — $DFF106 (ECS Denise only)
|
||||
|
||||
New bitplane/sprite control register — see `chipset_ecs.md` for full bit definition.
|
||||
|
||||
### DENISEID — $DFF07C (read only, ECS+)
|
||||
|
||||
Chip identification — see `chipset_ecs.md`.
|
||||
|
||||
## Changed / Extended Registers
|
||||
|
||||
### BPLCON0 — $DFF100
|
||||
|
||||
OCS BPLCON0 bit 0 (`ECSENA`) is reserved (must be 0) on OCS. On ECS:
|
||||
```
|
||||
bit 0: ECSENA — 1 = enable ECS features (required to use BPLCON3 etc.)
|
||||
```
|
||||
|
||||
Must set `ECSENA=1` before programming ECS-specific display modes.
|
||||
|
||||
### DIWSTRT / DIWSTOP — $DFF08E / $DFF090
|
||||
|
||||
OCS: 8-bit vertical and 8-bit horizontal (limited range).
|
||||
|
||||
ECS: `DIWHIGH` ($DFF1E4) extends these to full 12-bit resolution:
|
||||
|
||||
### DIWHIGH — $DFF1E4 (ECS only)
|
||||
|
||||
```
|
||||
bit 15: FLOP1 — playfield 1 window high bit
|
||||
bit 7: FLOP0 — playfield 0 window high bit
|
||||
bit 13-8: HB7-2 — horizontal window stop bits [7:2]
|
||||
bit 5-0: HS7-2 — horizontal window start bits [7:2]
|
||||
```
|
||||
|
||||
Allows the display window to be positioned anywhere in the extended beam range, enabling full overscan without copper tricks.
|
||||
|
||||
### FMODE — $DFF1FC (ECS read, AGA write)
|
||||
|
||||
On ECS, `$DFF1FC` is reserved. On AGA it becomes the `FMODE` register (see AGA section).
|
||||
|
||||
## ECS-Only DMA Extended Mode
|
||||
|
||||
Super Agnus extends the chip bus to allow DMA access across the full 2 MB range. No register change is needed — the chip detects the extended address automatically based on the installed RAM size and its internal revision.
|
||||
|
||||
## Programming Notes
|
||||
|
||||
> [!WARNING]
|
||||
> **OCS compatibility:** Never write to `BEAMCON0`, `BPLCON3`, or `DIWHIGH` on OCS hardware — the addresses are not decoded on OCS and writes may corrupt adjacent chip state or have undefined effects. Always check `GfxBase->ChipRevBits0` before writing ECS registers.
|
||||
|
||||
Safe ECS register programming pattern:
|
||||
```c
|
||||
#include <graphics/gfxbase.h>
|
||||
|
||||
extern struct GfxBase *GfxBase;
|
||||
|
||||
void set_pal_mode(void) {
|
||||
if (GfxBase->ChipRevBits0 & (1 << GFXB_HR_AGNUS)) {
|
||||
/* Safe to write BEAMCON0 */
|
||||
volatile UWORD *beamcon0 = (UWORD *)0xDFF1DC;
|
||||
*beamcon0 = 0x0020; /* PAL */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — ECS register descriptions
|
||||
- NDK39: `hardware/custom.h` (note: some ECS registers not in OCS struct)
|
||||
- AmigaMail Vol. 2 — ECS programming tutorials
|
||||
- *Amiga Hardware Reference Manual* 3rd ed. — Appendix F
|
||||
114
01_hardware/ecs_a600_a3000/gary_gayle.md
Normal file
114
01_hardware/ecs_a600_a3000/gary_gayle.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [ECS](README.md)
|
||||
|
||||
# Gary & Gayle — System Controller Chips
|
||||
|
||||
## Gary (A3000)
|
||||
|
||||
**Gary** is the custom system controller chip in the A3000, combining functions that are discrete ICs on the A2000:
|
||||
|
||||
- **Bus controller**: Manages the interaction between 68030/68882, chip bus, and Zorro III
|
||||
- **Auto-config controller**: Runs the Zorro expansion enumeration
|
||||
- **DMA arbitration**: Between 68030, custom chips, and Zorro III DMA
|
||||
- **SCSI interface glue**: Works with the A3000's built-in WD33C93 SCSI controller
|
||||
- **ROM decode**: Maps Kickstart ROM into the address space
|
||||
|
||||
Gary is not directly programmable by user software; its configuration is set by hardware strapping and the ROM initialisation sequence.
|
||||
|
||||
## Gayle (A600 / A1200)
|
||||
|
||||
**Gayle** is the custom chip providing **IDE** and **PCMCIA** interface on the A600 and A1200. The A600 and A1200 use different Gayle revisions with different PCMCIA pinouts.
|
||||
|
||||
### Gayle Identification
|
||||
|
||||
```
|
||||
A600 Gayle revision ID: read from $DA8000
|
||||
A1200 Gayle revision ID: read from $DA8000
|
||||
```
|
||||
|
||||
```asm
|
||||
move.b $DA8000, d0 ; Read Gayle ID byte
|
||||
```
|
||||
|
||||
| Byte | Machine |
|
||||
|---|---|
|
||||
| $D0 | A600 Gayle |
|
||||
| $D1 | A1200 Gayle (revision 1) |
|
||||
|
||||
### Gayle Register Map (A600/A1200)
|
||||
|
||||
| Address | Register | Description |
|
||||
|---|---|---|
|
||||
| $DA8000 | GAYLE_ID | Chip ID (read shifts bits) |
|
||||
| $DA9000 | GAYLE_INT_STATUS | Interrupt status |
|
||||
| $DA9004 | GAYLE_INT_ENABLE | Interrupt enable |
|
||||
| $DA9008 | GAYLE_CONTROL | Control register |
|
||||
|
||||
### IDE Interface
|
||||
|
||||
The IDE interface via Gayle is at `$DA0000` (A1200) or `$DA0000` (A600):
|
||||
|
||||
| Offset | Register | Description |
|
||||
|---|---|---|
|
||||
| $DA0000 | DATA | IDE data register (16-bit) |
|
||||
| $DA0004 | ERROR/FEATURE | Error (read) / Feature (write) |
|
||||
| $DA0008 | SECTOR_COUNT | Sector count |
|
||||
| $DA000C | SECTOR_NUMBER | Sector number (LBA 7:0) |
|
||||
| $DA0010 | CYLINDER_LOW | Cylinder low (LBA 15:8) |
|
||||
| $DA0014 | CYLINDER_HIGH | Cylinder high (LBA 23:16) |
|
||||
| $DA0018 | DRIVE_HEAD | Drive/Head/LBA (LBA 27:24) |
|
||||
| $DA001C | STATUS/COMMAND | Status (read) / Command (write) |
|
||||
| $DA101C | ALT_STATUS | Alternate status (no interrupt clear) |
|
||||
| $DA101C | DEVICE_CONTROL | Device control (write) |
|
||||
|
||||
> [!NOTE]
|
||||
> On the A1200, IDE registers are byte-wide on odd addresses in a 16-bit window. The data register is 16-bit. This differs from standard PC IDE — byte lanes are swapped relative to x86 convention.
|
||||
|
||||
### PCMCIA Interface (A600/A1200)
|
||||
|
||||
The A600 and A1200 support a Type II PCMCIA (PC Card) slot:
|
||||
|
||||
| Address Range | Type | Description |
|
||||
|---|---|---|
|
||||
| $600000–$9FFFFF | Attribute memory | Card configuration (CIS access) |
|
||||
| $A00000–$A3FFFF | Common memory | Modem/network card data |
|
||||
| $A40000–$A7FFFF | Common memory (cont.) | |
|
||||
| $600000 (Gayle) | Gayle attribute | Gayle own config space |
|
||||
|
||||
PCMCIA interrupt routing: Card interrupt → Gayle → CIA-A (`/FLG` pin) → CPU IPL 6.
|
||||
|
||||
### Gayle Interrupt Bits
|
||||
|
||||
```c
|
||||
/* DA9000 GAYLE_INT_STATUS */
|
||||
#define GAYLE_IRQ_IDE (1<<6) /* IDE drive interrupt */
|
||||
#define GAYLE_IRQ_CARD (1<<5) /* PCMCIA card interrupt */
|
||||
#define GAYLE_IRQ_BVD1 (1<<4) /* PCMCIA battery voltage 1 */
|
||||
#define GAYLE_IRQ_BVD2 (1<<3) /* PCMCIA battery voltage 2 */
|
||||
#define GAYLE_IRQ_WP (1<<2) /* PCMCIA write protect */
|
||||
#define GAYLE_IRQ_CD (1<<1) /* PCMCIA card detect */
|
||||
```
|
||||
|
||||
### Gayle Power Control
|
||||
|
||||
Gayle controls PCMCIA card power (5V / 3.3V on A1200 rev 1D+):
|
||||
```c
|
||||
/* GAYLE_CONTROL bits */
|
||||
#define GAYLE_POW (1<<7) /* PCMCIA power on */
|
||||
#define GAYLE_WS (1<<6) /* wait states for PCMCIA */
|
||||
```
|
||||
|
||||
## AmigaOS IDE Access
|
||||
|
||||
AmigaOS accesses the Gayle IDE through the `scsi.device` or dedicated `ata.device` driver provided with OS 3.1+. Direct IDE programming is done in the filesystem handler (`trackdisk.device` replacement).
|
||||
|
||||
The standard path:
|
||||
```
|
||||
Application → dos.library → File System Handler → scsi.device → Gayle IDE
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- Commodore A600 Technical Reference Manual — Gayle chapter
|
||||
- Commodore A1200 Technical Reference Manual — Gayle chapter
|
||||
- ADCD 2.1 — `Devices_Manual_guide/` scsi.device
|
||||
- NDK39: `hardware/gayle.h` (if present), community-documented Gayle registers
|
||||
97
01_hardware/ecs_a600_a3000/productivity_modes.md
Normal file
97
01_hardware/ecs_a600_a3000/productivity_modes.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
[← Home](../../README.md) · [Hardware](../README.md) · [ECS](README.md)
|
||||
|
||||
# ECS Productivity & Multiscan Display Modes
|
||||
|
||||
## Overview
|
||||
|
||||
ECS introduces **BEAMCON0** which allows the Amiga to produce non-standard display timings. The most useful are **productivity mode** (~28 kHz / 31 kHz horizontal) and **multiscan mode**, which provide flicker-free, high-resolution displays compatible with standard SVGA monitors.
|
||||
|
||||
These modes are available on A3000 and some A2000/A600 configurations with a multisync monitor.
|
||||
|
||||
## Standard OCS Timings (for reference)
|
||||
|
||||
| Mode | H rate | V rate | Resolution |
|
||||
|---|---|---|---|
|
||||
| PAL LORES | 15.625 kHz | 50 Hz | 320×256 |
|
||||
| PAL HIRES | 15.625 kHz | 50 Hz | 640×256 |
|
||||
| NTSC LORES | 15.720 kHz | 60 Hz | 320×200 |
|
||||
| NTSC HIRES | 15.720 kHz | 60 Hz | 640×200 |
|
||||
| PAL interlace | 15.625 kHz | 50 Hz (25 Hz/field) | 320×512 / 640×512 |
|
||||
|
||||
## ECS Multiscan Modes
|
||||
|
||||
| Mode | H rate | V rate | Resolution | BEAMCON0 |
|
||||
|---|---|---|---|---|
|
||||
| Productivity | ~28.6 kHz | 57 Hz | 640×480 | $0A00 |
|
||||
| Super72 | ~28.6 kHz | 72 Hz | 800×600 (approx) | varies |
|
||||
| DblPAL | 31.25 kHz | 50 Hz | 640×512 | custom |
|
||||
| DblNTSC | 31.47 kHz | 60 Hz | 640×400 | custom |
|
||||
| VGA-like | 31.47 kHz | 60 Hz | 640×480 | custom |
|
||||
|
||||
## Programming Productivity Mode
|
||||
|
||||
Productivity mode on the A3000 (PAL, 640×480):
|
||||
|
||||
```asm
|
||||
; Set BEAMCON0 for variable beam timing
|
||||
move.w #$0A00, $DFF1DC ; VARBEAMEN | VARVSYEN
|
||||
|
||||
; Program horizontal total, sync, blank (custom timing)
|
||||
move.w #$71, $DFF1C0 ; HTOTAL (horizontal total - 1)
|
||||
move.w #$0F, $DFF1C4 ; HSSTRT (H sync start)
|
||||
move.w #$19, $DFF1C6 ; HSSTOP (H sync stop)
|
||||
move.w #$09, $DFF1C8 ; HBSTRT (H blank start)
|
||||
move.w #$71, $DFF1CA ; HBSTOP (H blank stop)
|
||||
|
||||
; Vertical timing
|
||||
move.w #$0242, $DFF1E0 ; VTOTAL
|
||||
move.w #$0015, $DFF1E6 ; VSSTRT
|
||||
move.w #$001D, $DFF1E8 ; VSSTOP
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> The exact register values depend on the target monitor's sync requirements. The A3000's monitor (1084S or Commodore 1950) has a specific timing window. Always consult the monitor's datasheet.
|
||||
|
||||
## OS Support: ScreenModes
|
||||
|
||||
AmigaOS 3.1 integrates ECS productivity modes through the **screenmode** system:
|
||||
|
||||
```c
|
||||
#include <graphics/modeid.h>
|
||||
#include <libraries/asl.h>
|
||||
|
||||
/* Open a 640×480 productivity screen */
|
||||
struct Screen *scr = OpenScreenTags(NULL,
|
||||
SA_DisplayID, PRODDBL_MONITOR_ID | HIRES_KEY,
|
||||
SA_Width, 640,
|
||||
SA_Height, 480,
|
||||
SA_Depth, 4,
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
**Key mode IDs for ECS:**
|
||||
```c
|
||||
#define MULTISCAN_MONITOR_ID 0x00041000 /* multiscan / productivity */
|
||||
#define SUPER72_MONITOR_ID 0x00081000
|
||||
#define DBLNTSC_MONITOR_ID 0x00401000
|
||||
#define DBLPAL_MONITOR_ID 0x00421000
|
||||
```
|
||||
|
||||
These IDs are returned by `BestModeID()` and accepted by `OpenScreen()` / `OpenScreenTags()`.
|
||||
|
||||
## Hardware Requirements
|
||||
|
||||
- **ECS chipset** (Super Agnus + ECS Denise) — required for BEAMCON0
|
||||
- **Multisync monitor** — standard 15 kHz PAL/NTSC monitors do not support 31 kHz
|
||||
- **A3000** — has built-in multiscan support; A2000 requires a separate scan doubler card
|
||||
|
||||
## Flicker Fixer (A2000/A500)
|
||||
|
||||
Some Zorro II cards (e.g., Flicker Fixer by MicroWay, Indivision ECS) scan-double the 15 kHz signal to 31 kHz for use with VGA monitors. These operate transparently — no BEAMCON0 programming needed.
|
||||
|
||||
## References
|
||||
|
||||
- ADCD 2.1 Hardware Manual — ECS display modes
|
||||
- AmigaMail Vol. 2 — ECS multiscan articles
|
||||
- NDK39: `graphics/modeid.h` — monitor mode IDs
|
||||
- A3000 Technical Reference Manual — display timing chapter
|
||||
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