mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
More content
This commit is contained in:
parent
9b0dfbcf32
commit
a59d8350b3
6 changed files with 1674 additions and 19 deletions
|
|
@ -10,7 +10,7 @@ The Amiga graphics system is built on custom DMA-driven hardware (Agnus/Alice +
|
|||
|---|---|
|
||||
| [gfx_base.md](gfx_base.md) | GfxBase structure, chipset detection (OCS/ECS/AGA), PAL/NTSC, display pipeline (MakeVPort/MrgCop/LoadView), blitter queue |
|
||||
| [bitmap.md](bitmap.md) | BitMap structure, planar layout, allocation |
|
||||
| [display_modes.md](display_modes.md) | Chipset comparison (OCS/ECS/AGA), ModeID system, PAL/NTSC timing, DMA slot budget |
|
||||
| [display_modes.md](display_modes.md) | Full chipset comparison, ModeID selection flowchart, CRT vs flat-panel, interlace/progressive tradeoffs, named antipatterns, FPGA/MiSTer impact, historical context, modern analogies, FAQ |
|
||||
| [ham_ehb_modes.md](ham_ehb_modes.md) | HAM6/HAM8 encoding pipeline, EHB half-brite, fringing, palette programming, FPGA decoder logic |
|
||||
| [copper.md](copper.md) | Copper coprocessor, instruction format, UCopList |
|
||||
| [copper_programming.md](copper_programming.md) | Copper deep dive: architecture, copper list construction, gradient and raster effects |
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ Pixel clock (hires): 14,318,180 Hz
|
|||
```
|
||||
←── Horizontal line (~64 µs PAL) ──→
|
||||
┌───────────────────────────────────────────────────────────┐
|
||||
│ HSYNC │ Left │ Active Display Area │ Right │
|
||||
│ │Border │ (bitplane DMA + sprite DMA) │Border │
|
||||
│ ~4.7µs│ │ │ │
|
||||
│ HSYNC │ Left │ Active Display Area │ Right │
|
||||
│ │ Border │ (bitplane DMA + sprite DMA) │ Border │
|
||||
│ ~4.7µs│ │ │ │
|
||||
└───────────────────────────────────────────────────────────┘
|
||||
|
||||
Vertical:
|
||||
|
|
@ -205,13 +205,441 @@ The display system shares DMA bandwidth with other custom chips. Each scanline h
|
|||
|
||||
> In high-resolution 4-plane mode, bitplane DMA alone consumes 80 words per line — nearly the entire available bandwidth. This is why OCS/ECS hires is limited to 4 planes (16 colors) and AGA needed wider fetch modes.
|
||||
|
||||
---
|
||||
## ModeID Selection Flowchart
|
||||
|
||||
Choosing the right display mode requires answering four questions in order: monitor type → resolution needs → color depth → interlacing preference.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Q1["What monitor?"] --> |"15 kHz RGB (1084, TV)"| Q2["Resolution?"]
|
||||
Q1 --> |"31 kHz VGA (DBLPAL/DBLNTSC)"| Q3["Depth?"]
|
||||
Q1 --> |"RTG card (CyberGraphX/P96)"| RTG["Use RTG ModeIDs<br/>not native graphics"]
|
||||
|
||||
Q2 --> |"Lowres 320px"| LORES["PAL:LORES / NTSC:LORES<br/>$00000000 / $00000000"]
|
||||
Q2 --> |"Hires 640px"| HIRES["PAL:HIRES / NTSC:HIRES<br/>$00008000"]
|
||||
Q2 --> |"SuperHires 1280px<br/>(ECS+ only)"| SUPER["PAL:SUPERHIRES<br/>$00080000"]
|
||||
|
||||
Q3 --> |"8-bit (256 colors)"| DBL8["DBLPAL/NTSC HIRES<br/>$00039004 / $00011004"]
|
||||
Q3 --> |"4–5 bit"| DBL4["DBLPAL/NTSC LORES<br/>$00039000 / $00011000"]
|
||||
|
||||
LORES --> |"Need 6 planes?"| LACE["> Check if LACE needed"]
|
||||
HIRES --> |"Limited to 4 planes<br/>due to DMA budget"| LACE
|
||||
SUPER --> |"Limited to 2 planes"| LACE
|
||||
```
|
||||
|
||||
###encoding intoc decision logic
|
||||
|
||||
```c
|
||||
/* Complete mode selection routine handling chipset fallback: */
|
||||
ULONG SelectBestMode(ULONG wantWidth, ULONG wantHeight, ULONG wantDepth)
|
||||
{
|
||||
ULONG modeID = INVALID_ID;
|
||||
|
||||
/* Step 1: Try exact match via BestModeID */
|
||||
modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, wantWidth,
|
||||
BIDTAG_NominalHeight, wantHeight,
|
||||
BIDTAG_Depth, wantDepth,
|
||||
TAG_DONE);
|
||||
|
||||
if (modeID != INVALID_ID)
|
||||
return modeID;
|
||||
|
||||
/* Step 2: Fall back — halve depth, try again */
|
||||
if (wantDepth > 4)
|
||||
{
|
||||
modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, wantWidth,
|
||||
BIDTAG_NominalHeight, wantHeight,
|
||||
BIDTAG_Depth, wantDepth / 2,
|
||||
TAG_DONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Step 3: Dichotomy fallback —attempt lores non-laced */
|
||||
modeID = BestModeID(
|
||||
BIDTAG_Depth, 4,
|
||||
TAG_DONE);
|
||||
}
|
||||
|
||||
return modeID; /* may still be INVALID_ID — caller must check */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CRT vs Flat-Panel Considerations
|
||||
|
||||
The Amiga's display timing was designed for **15 kHz CRT televisions** and monitors. Modern flat-panel displays introduce several compatibility issues:
|
||||
|
||||
| Concern | CRT (Original) | Modern Flat-Panel | Workaround |
|
||||
|---|---|---|---|
|
||||
| **Sync frequency** | 15.625 kHz (PAL) / 15.734 kHz (NTSC) | Most LCDs require ≥ 31 kHz | Use DBLPAL/DBLNTSC modes or scandoubler (Indivision, OSSC) |
|
||||
| **Refresh rate** | 50 Hz (PAL) / 60 Hz (NTSC) | Many monitors reject < 56 Hz | Force NTSC 60 Hz on PAL systems for LCD compatibility |
|
||||
| **Interlacing** | Natural — phosphor persistence smooths flicker | Native progressive; interlace flicker is ugly and fatiguing | Use non-laced modes or flicker fixer |
|
||||
| **Pixel aspect ratio** | Non-square (PAL: 1.39:1, NTSC: 0.91:1) | Square pixels | Stretch to 4:3 in emulators; accept on real hardware |
|
||||
| **Overscan** | ~15% of image hidden in bezel | Shows full raster — exposed borders look broken | Pad content or enable bezel cropping |
|
||||
|
||||
### The Scandoubler Problem
|
||||
|
||||
Scandoublers (Indivision AGA, OSSC, Retrotink) convert 15 kHz RGB to 31+ kHz for VGA/HDMI. This solves the sync problem but introduces:
|
||||
|
||||
- **1–2 frame latency** — frame-accurate timing becomes frame+1 at best
|
||||
- **Copper-synced effects may tear** — the scandoubler and Amiga don't share a clock
|
||||
- **Color fidelity** — analog RGB → digital conversion can clip super-white ($FFF) or super-black
|
||||
|
||||
> [!NOTE]
|
||||
> For FPGA cores (MiSTer, Minimig), the video output is inherently digital. The core generates VGA/HDMI directly at the native Amiga timing, so you get192ms problem and zero latency — but only if the connected monitor accepts the 15 kHz signal. Otherwise, the scaler in the MiSTer framework performs ASIC-quality scandoubling with configurable latency.
|
||||
|
||||
---
|
||||
|
||||
## Interlace vs Progressive — Tradeoffs
|
||||
|
||||
Interlacing doubles vertical resolution at the cost of flicker. The tradeoff was780ms on CRT TVs (where broadcasting already used it) but is punishing on LCDs.
|
||||
|
||||
| Aspect | Progressive (non-laced) | Interlaced (LACE) |
|
||||
|---|---|---|
|
||||
| **Vertical resolution** | 256 (PAL) / 200 (NTSC) | 512 (PAL) / 400 (NTSC) |
|
||||
| **Flicker** | None | 25 Hz (PAL) / 30 Hz (NTSC) per field — pronounced on bright single-pixel lines |
|
||||
| **CRT experience** | Solid, smooth | Visible shimmer on horizontal edges; phosphor persistence helps |
|
||||
| **LCD experience** |ning | Harsh flicker — every other line alternates on/off at 25/*30 Hz |
|
||||
| **DMA cost** | Standard | Double — two fields = double bitplane DMA |
|
||||
| **Copper effects** | per-frame | Must track which field is active (LONG FRAME vs SHORT FRAME) |
|
||||
| **Use case** | Games, demos, most applications | Static UI (text is readable at higher res), still images |
|
||||
|
||||
### AGADBLPAL/DBLNTSC as a Flicker-Free486ms
|
||||
|
||||
AGA introduced DBLPAL and DBLNTSC — 31 kHz progressive modes that display 256/512 lines without interlacing. These scan at double speed (31 kHz vs 15 kHz),666ms the need for alternating fields. The cost: **double the pixel clock** → wider fetch modes required → 4× FMODE. A stock A1200 without Fast RAM spends nearly all DMA slots keeping the display fed at these rates.
|
||||
|
||||
```c
|
||||
/* DBLPAL non-laced — 640×512 progressive on AGA */
|
||||
modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, 640,
|
||||
BIDTAG_NominalHeight, 512,
|
||||
BIDTAG_Depth, 8,
|
||||
BIDTAG_MonitorID, PAL_MONITOR_ID,
|
||||
TAG_DONE);
|
||||
/* ModeID will be DBLPAL:HIRES-LACE if fast enough, or a slower fallback */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Named Antipatterns
|
||||
|
||||
### 1. "The Hardcoded Mode"
|
||||
|
||||
**What fails** — assuming a specific ModeID exists on the user's hardware:
|
||||
|
||||
```c
|
||||
/* BROKEN — assumes PAL:Lowres always available */
|
||||
ULONG modeID = 0x00000000; /* PAL:LORES Keyed */
|
||||
OpenScreenTags(NULL,
|
||||
SA_DisplayID, modeID,
|
||||
SA_Depth, 5,
|
||||
TAG_DONE);
|
||||
/* Fails on NTSC machines or setups without native chipset */
|
||||
```
|
||||
|
||||
**Why it fails:** PAL:LORES ($00000000) is not guaranteed on NTSC-only machines. Even on PAL systems, a RTG-only setup (e.g. Picasso IV primary display) has no native chipset modes. `SA_DisplayID` with a hardcoded value bypasses fallback logic.
|
||||
|
||||
**Correct:**
|
||||
|
||||
```c
|
||||
/* Query the database for the best available mode: */
|
||||
ULONG modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, 320,
|
||||
BIDTAG_NominalHeight, 256,
|
||||
BIDTAG_Depth, 5,
|
||||
TAG_DONE);
|
||||
|
||||
if (modeID != INVALID_ID)
|
||||
{
|
||||
OpenScreenTags(NULL,
|
||||
SA_DisplayID, modeID,
|
||||
SA_Depth, 5,
|
||||
TAG_DONE);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. "The Depth Ostrich"
|
||||
|
||||
**What fails** — requesting depth without checking chipset limits:
|
||||
|
||||
```c
|
||||
/* BROKEN — 256 colors on OCS */
|
||||
struct Screen *scr = OpenScreenTags(NULL,
|
||||
SA_Depth, 8, /* 256 colors — needs AGA */
|
||||
SA_DisplayID, PAL_MONITOR_ID | HIRES,
|
||||
TAG_DONE);
|
||||
/* scr is NULL on OCS/ECS — no fallback */
|
||||
```
|
||||
|
||||
**Why it fails:** OCS/ECS support at most 6 bitplanes (EHB for 64 colors; HAM6 for 4096 via palette tricks). 8 plane modes require AGA. `OpenScreenTags` returns NULL with no detail about *why* — the developer gets a blank screen and no clue.
|
||||
|
||||
**Correct:**
|
||||
|
||||
```c
|
||||
/* Check chipset capabilities first: */
|
||||
ULONG maxPlanes = 6; /* OCS/ECS default */
|
||||
if (GfxBase->DisplayFlags & AGF_AGA)
|
||||
maxPlanes = 8;
|
||||
|
||||
ULONG wantDepth = (wantColor > (1L << maxPlanes)) ? maxPlanes : wantColor;
|
||||
|
||||
struct Screen *scr = OpenScreenTags(NULL,
|
||||
SA_Depth, wantDepth,
|
||||
SA_DisplayID, PAL_MONITOR_ID | HIRES,
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. "The LACE Without Thought"
|
||||
|
||||
**What fails** — turning on interlace without understanding thecho832ms:
|
||||
|
||||
```c
|
||||
/* BROKEN — the flag is harmless, right? */
|
||||
modeID |= LACE;
|
||||
OpenScreenTags(NULL,
|
||||
SA_DisplayID, modeID,
|
||||
TAG_DONE);
|
||||
/* Flicker city on LCD, double DMA for no benefit */
|
||||
```
|
||||
|
||||
**Why it fails:** LACE bit doubles DMA consumption per frame and introduces 25/30 Hz flicker. On aalenibbon LCD the flicker is unbearable for text work. Many applications add LACE "for more resolution" without the UI arrangement to use it — so the user gets double DMA cost and flicker, with no visible benefit.
|
||||
|
||||
**Correct:**
|
||||
|
||||
```c
|
||||
/* Only add LACE if you genuinely need >256 visible lines: */
|
||||
if (minVisibleLines > 256)
|
||||
{
|
||||
modeID |= LACE;
|
||||
/* Plan: use every-other-line rendering to reduce flicker */
|
||||
/* OR: use DBLPAL on AGA for flicker-free vertical doubling */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. "The ModeID Bit-Whacker"
|
||||
|
||||
**What fails** — OR'ing flags into a ModeID without understanding the encoding:
|
||||
|
||||
```c
|
||||
/* BROKEN —does this even mean? */
|
||||
ULONG magicMode = PAL_MONITOR_ID | HIRES | LACE | HAM | EHB | 0x0008;
|
||||
/* bits collide — HAM + EHB + 8 planes is193ms nonsense combination */
|
||||
```
|
||||
|
||||
**Why it fails:** ModeID bits arepositional but map to specific781ms flags. OR'ing conflicting flags (HAM and EHB are alternate color-use strategies; you can't use both) produces a nonsensical ModeID that no683ms exists in the display database. `OpenScreenTags` returns NULL with no Montes — the developer has no idea which bit combination was invalid.
|
||||
|
||||
**Correct:**
|
||||
|
||||
```c
|
||||
/* Use BestModeID — let the OS resolve the bit conflicts: */
|
||||
ULONG modeID = BestModeID(
|
||||
BIDTAG_NominalWidth, wantWidth,
|
||||
BIDTAG_NominalHeight, wantHeight,
|
||||
BIDTAG_Depth, wantDepth,
|
||||
TAG_DONE);
|
||||
/* BestModeID resolves bit conflicts internally */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. "The `FMODE` Faith-Healer"
|
||||
|
||||
**What fails** — setting `FMODE = 3` without checking for AGA or understanding the side-effects:
|
||||
|
||||
```c
|
||||
/* BROKEN — writes to register that doesn't exist on OCS */
|
||||
custom->fmode = 3; /* 4× fetch — maximum bandwidth */
|
||||
/*ìodes OCS systems: write to $DFF1FC, which is a mirror
|
||||
|
||||
```
|
||||
|
||||
**Why it fails:** `FMODE` exists only on AGA (Lisa chip). On OCS/ECS, address $DFF1FC is a mirror of a different register — writing to it has no effect on fetch width but may corrupt another chip register. Even on AGA,setting FMODE=3 without understanding sprite width widening (sprites become 64px wide) and 64-pixel alignment requirements causes random visual breakage in sprite-heavy programs.
|
||||
|
||||
**Correct:**
|
||||
|
||||
```c
|
||||
/* Check AGA before touching FMODE: */
|
||||
if (GfxBase->DisplayFlags & AGF_AGA)
|
||||
{
|
||||
UBYTE wantFMODE = 0; /* default: OCS-compatible */
|
||||
|
||||
if (wantWidth > 640 || wantDepth > 6)
|
||||
wantFMODE = 1; /* 2× fetch for superhires or 7-plane */
|
||||
if (wantWidth > 1280 || wantDepth > 7)
|
||||
wantFMODE = 3; /* 4× forexotic combinations */
|
||||
|
||||
custom->fmode = wantFMODE;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Pitfalls
|
||||
|
||||
### 1. DMA Starvation Under Load
|
||||
|
||||
When bitplane DMA consumes most of a scanline, the CPU gets virtually no cycles. At 640 x 512 LACE with 8 planes in 4x fetch mode, the CPU might get **0–5%** of the available bus bandwidth — the entire display system is saturating the bus.
|
||||
|
||||
```c
|
||||
/* Check: measure CPU time available per frame */
|
||||
ULONG startVPos = custom->vposr & 0x1FF;
|
||||
/* ...do work... */
|
||||
ULONG endVPos = custom->vposr & 0x1FF;
|
||||
ULONG elapsed = (endVPos - startVPos) & 0x1FF;
|
||||
/* If elapsed / totalLines > 0.9, CPU is starved */
|
||||
```
|
||||
|
||||
### 2. Overscan Assumptions
|
||||
|
||||
Programs that assume the user has overscan "swallowing" the border area produce content that bleeds into visible display on LCD setups. Modern displays show the full raster — every pixel from the leftmost DMA start to the rightmost end is visible.
|
||||
|
||||
```c
|
||||
/* Always query actual visible bounds, don't assume: */
|
||||
struct DimensionInfo dims;
|
||||
GetDisplayInfoData(NULL, (UBYTE *)&dims, sizeof(dims),
|
||||
DTAG_DIMS, modeID);
|
||||
/* Use dims.Nominal.MinX/MaxX/MinY/MaxY for real bounds */
|
||||
```
|
||||
|
||||
### 3. PAL/NTSC Assumptions in Timing Code
|
||||
|
||||
Hardcoded line counts break when a program runs on the opposite video standard:
|
||||
|
||||
```c
|
||||
/* BROKEN — assumes 256 active lines */
|
||||
#define SCREEN_LINES 256
|
||||
/* On NTSC, there are only 200 active lines — bottom 56 lines
|
||||
are off-screen, and Copper split-point alignment falls apart */
|
||||
```
|
||||
|
||||
**Correct:**
|
||||
|
||||
```c
|
||||
/* Query the actual display info */
|
||||
struct DimensionInfo dims;
|
||||
GetDisplayInfoData(NULL, (UBYTE *)&dims, sizeof(dims),
|
||||
DTAG_DIMS, modeID);
|
||||
ULONG screenLines = dims.Nominal.MaxY - dims.Nominal.MinY + 1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always query via `BestModeID`** — never hardcode ModeID values. Let the display database do the work.
|
||||
2. **Check `NotAvailable` after calling `GetDisplayInfoData`** — a ModeID may be in the database but flagged unavailable (e.g. needs a monitor that isn't attached).
|
||||
3. **Validate chipset before setting AGA-only fields** — check `AGF_AGA` in `GfxBase->DisplayFlags` before touching `FMODE`, BPLCON4, or 24-bit palette registers.
|
||||
4. **Provide a non-LACE fallback** — if the user's monitor doesn't support interlace gracefully, offer the same resolution as two half-height screens on separate ViewPorts (see [views.md](views.md), ViewPort chaining).
|
||||
5. **Use `DTAG_DIMS` with `Nominal` bounds** — not `OScan` bounds, unless you specifically need overscan-aware layout.
|
||||
6. **Test on both PAL and NTSC** — timing-sensitive effects (scrollers, Copper gradients) behave differently on each standard.
|
||||
7. **Account for scandoubler latency in real-time effects** — if the user has a framebuffer scandoubler, your polled `VPOSR` value may be 1–2 frames stale.
|
||||
8. **Don't set `FMODE` just for fun** — it changes sprite widths and alignment. Set it once at display init and leave it.
|
||||
|
||||
---
|
||||
|
||||
## When to Use / When NOT to Use
|
||||
|
||||
| Scenario | Use | Avoid |
|
||||
|---|---|---|
|
||||
| Portable application for all Amigas | `BestModeID` with depth-based fallback | Hardcoded ModeID |
|
||||
| Game at 320 x 256, 32 colors | PAL:LORES, 5 planes | HAM (too slow for scrolling; fringing artifacts on movement) |
|
||||
| Static image viewer | HAM8 (262,144 colors, 8 planes) | 5-plane mode (limited palette) |
|
||||
| Word processor | PAL:HIRES, 2 planes (readable text) | HAM (fringing on text edges) |
|
||||
| Demo with Copper effects | Lowres, 5–6 planes (DMA budget for Copper) | Highres (Copper loses slots to bitplane DMA) |
|
||||
| RTG system with graphics card | CyberGraphX/P96 ModeID, not native | Native Amiga mode on RTG monitor |
|
||||
| FPGA/MiSTer display | DBLPAL/DBLNTSC for 31-kHz HDMI | 15-kHz output unless monitor supports it |
|
||||
|
||||
---
|
||||
|
||||
## FPGA & MiSTer Impact
|
||||
|
||||
Display mode reproduction on FPGA is **primarily about timing**, not resolution or color depth:
|
||||
|
||||
| Concern | Why It Matters | FPGA State |
|
||||
|---|---|---|
|
||||
| **Pixel clock accuracy** | 7.093790 MHz (PAL) vs 7.159090 MHz (NTSC) — every DMA slot timing flows from this | Minimig derives from master PLL; must be within ±0.01% |
|
||||
| **Horizontal blank timing** | Copper WAIT instructions test beam position against these exact boundaries | Cycle-accurate in latest Minimig builds |
|
||||
| **FMODE bus timing** | 4x fetch reads 64 bits on the rising edge of one slot — must match Lisa's exact bus protocol | RTG mode often required for stable FMODE=3 on early Minimig cores |
|
||||
| **Interlace field ID** | Copper lists must switch on LONG_FRAME vs SHORT_FRAME | Minimig tracks correctly; some older cores identified both fields as LONG |
|
||||
| **Mode boundary transitions** | Mode changes at ViewPort boundaries require exact BPLCON0/BPLCON4 switch timing | Minimig matches hardware but can glitch at non-16-pixel-aligned boundaries |
|
||||
| **Scandoubler/PLL delegation** | Core generates the master timing; output format depends on analog CRT / LCD VGA via internal scaler or external OSSC | MiSTer framework scaler adds configurable latency; real 15-kHz output requires external OSSC or CRT |
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If writing demos or effects that depend on exact beam-position timing, test on a cycle-accurate Minimig core. Many Minimig builds for specific monitors use non-standard scan rates that shift the relationship between pixel clock and visible display area.
|
||||
|
||||
---
|
||||
|
||||
## Historical Context & Modern Analogies
|
||||
|
||||
### 1985 Competitive Landscape
|
||||
|
||||
The Amiga could switch between different color depths, resolutions, and scan rates — including mid-scanline via the Copper. Contemporary platforms had **one** display mode at a time:
|
||||
|
||||
| Platform | Resolution(s) | Colors | Mode Switching |
|
||||
|---|---|---|---|
|
||||
| **Amiga OCS (1985)** | 320 x 200 – 640 x 400 | 2 – 4096 (HAM6) | **Mid-screen** (via Copper), runtime changeable |
|
||||
| **C64 (1982)** | 160 x 200 – 320 x 200 | 16 | Fixed at boot; mode changes required register writes during VBlank |
|
||||
| **MS-DOS CGA (1981)** | 320 x 200 / 640 x 200 | 4 / 2 (mono) | One mode at a time; mode switch required register writes with briefly corrupt display |
|
||||
| **Atari ST (1985)** | 320 x 200 / 640 x 200 / 640 x 400 mono | 16 / 4 / 2 (mono) | Fixed at boot; no mid-screen mode change |
|
||||
| **Macintosh (1984)** | 512 x 342 | 1 (black & white) | Fixed — the PCB had no video mode connector |
|
||||
|
||||
The Amiga was the **sole** consumer platform that could display HAM still images beside a high-resolution text editor on a different screen that could be dragged down to reveal the previous one — in **1985**. Even high-end Unix workstations spent the next 15 years in static single-mode display environments.
|
||||
|
||||
### Modern Analogies
|
||||
|
||||
Many display techniques that feel commonplace today were actually baked into the Amiga's architecture:
|
||||
|
||||
| Amiga Concept | Modern Equivalent | Connection |
|
||||
|---|---|---|
|
||||
| `ModeID` / display database | EDID / DisplayPort descriptor blocks | Same architecture: database of capabilities queried at runtime |
|
||||
| AGA wider fetch modes (FMODE) | GPU memory bandwidth tiers (GDDR5/HBM2) | Same tradeoff: wider bus to feed more pixels per clock |
|
||||
| DBLPAL flicker-free progressive | macOS Retina @2x doubling of assets | Same pattern: double resolution without interlace |
|
||||
| **Scanline mid-frame mode change** (Copper) | **Nothing** — modern GPUs can't do this | GPU fragment shaders compute per-pixel but entire framebuffer is one resolution |
|
||||
| HAM compression (6/8 bits encoding 16-bit palette indices) | Texture compression (DXT, ASTC) | Same goal: represent more color in fewer bits per pixel, lossy at edges |
|
||||
| Display database query | macOS `CGDisplayCopyAllDisplayModes()` | Nearly the exact same API pattern, 15 years later |
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Can I mix OCS and AGA modes on the same screen?
|
||||
**No.** The chipset is set at power-on or early startup. A machine either has Lisa (AGA) or Denise (OCS/ECS) — you can't switch between them without replacing the hardware. `OpenScreen` with an AGA ModeID on an OCS machine returns NULL.
|
||||
|
||||
### Q: Why does SuperHires only give me 2 planes?
|
||||
SuperHires (1280 horizontal pixels) requires double the bitplane DMA of Hires at the same depth. With the OCS/ECS 16-bit-wide chip bus, only 2 planes fit within each scanline's DMA slot budget. AGA with 4x fetch can reach 4 planes at SuperHires.
|
||||
|
||||
### Q: Should I use HAM for a game?
|
||||
**Almost never.** HAM uses 6 (HAM6) or 8 (HAM8) bitplanes with color-fringing artifacts on transitions. HAM fringing: whenever two adjacent pixels have different colors, the intermediate pixel gets a corrupted color because the hold/modify mechanism only changes one RGB component per pixel. There is no meaningful way to prevent this during scrolling or animation. Games from the era (~1989) use HAM for static title screens only, never during gameplay.
|
||||
|
||||
### Q: What's the difference between LACE and DBLPAL?
|
||||
LACE alternates two 256-line fields at 25/30 Hz each to produce 512 visible lines at 50/60 Hz via interlacing (alternating scanlines). DBLPAL renders all 512 lines progressively at 31-kHz scan rate. DBLPAL requires a VGA-capable monitor (31 kHz) and AGA. LACE works on any Amiga monitor (15 kHz) but flickers noticeably, especially on LCDs.
|
||||
|
||||
### Q: My polled raster position gives corrupt values — why?
|
||||
`VPOSR` (read-only) returns the current beam position. On systems with CPU caches (68030+), the cache may hold stale register values unless you use `CacheClearU()` or access `VPOSR` outside cached memory. Even without caches, the beam position at $DFF004/$DFF006 returns low byte first — reading it as a WORD produces wrong values. Always read as two BYTE reads: `custom->vposr & 0xFF` then `(custom->vposr >> 8) & 0xFF`.
|
||||
|
||||
### Q: Can I create my own custom ModeID?
|
||||
**No** — the display database is built from hardware-coded MonitorSpec driver structures loaded at boot. Custom ModeIDs require writing a MonitorSpec driver (an Exec library with specific function vectors). See the [MonitorSpec documentation](https://wiki.amigaos.net/wiki/MonSpec) for details.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `graphics/displayinfo.h`, `graphics/modeid.h`, `graphics/gfxbase.h`
|
||||
- HRM: *Amiga Hardware Reference Manual* — Display chapters
|
||||
- ADCD 2.1: `NextDisplayInfo`, `GetDisplayInfoData`, `BestModeIDA`
|
||||
- See also: [views.md](views.md) — ViewPort and View construction
|
||||
- See also: [copper.md](copper.md) — Copper display list programming
|
||||
- See also: [ham_ehb_modes.md](ham_ehb_modes.md) — special display modes
|
||||
- NDK39: `graphics/displayinfo.h`, `graphics/modeid.h`, `graphics/gfxbase.h`, `graphics/monitor.h`
|
||||
- HRM: *Amiga Hardware Reference Manual* — Display, Custom Chip chapters
|
||||
- ADCD 2.1: `NextDisplayInfo`, `GetDisplayInfoData`, `BestModeIDA`, MonitorSpec autodocs
|
||||
- See also: [views.md](views.md) — ViewPort and View construction, mode transitions at ViewPort boundaries
|
||||
- See also: [copper.md](copper.md) — Copper display list programming, mid-screen mode switching
|
||||
- See also: [ham_ehb_modes.md](ham_ehb_modes.md) — HAM6/HAM8/EHB in depth
|
||||
- See also: [AGA Display Modes](../01_hardware/aga_a1200_a4000/aga_display_modes.md) — AGA-specific capabilities
|
||||
- See also: [Chipset AGA](../01_hardware/aga_a1200_a4000/chipset_aga.md) — Lisa chip, FMODE, 24-bit palette
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue