6845 CRTC
Motorola 6845-family Cathode-Ray-Tube Controller. Drives the raster scan: produces hsync/vsync, fetches video data addresses, drives the cursor signal, and reads the light-pen latch. The other half of the video pipeline is the video-ula, which receives video data and serialises it into RGB.
Not present on the Electron — Electron uses a single combined ULA that subsumes both jobs.
Programming interface
| Sheila | Direction | Purpose |
|---|---|---|
&FE00 | write | Address register — selects which internal register (5 bits) the next &FE01 access targets |
&FE01 | depends | Data — read/write the selected register (most are write-only) |
Preferred access pattern: use VDU 23,0,R,V,0,0,0,0,0,0 which is Tube-safe. Direct &FE00/&FE01 writes are faster but bypass the OS — fine on the I/O processor, fails over Tube. See naug-ch13-video §13.3.3.
Register map (18 registers, R0-R17)
| Reg | Width | Access | Function |
|---|---|---|---|
| R0 | 8 | W | Horizontal total (chars-per-line-1) |
| R1 | 8 | W | Horizontal displayed (chars per line) |
| R2 | 8 | W | Horizontal sync position |
| R3 | 8 | W | Sync widths (bits 0-3: hsync width in chars; bits 4-7: vsync width in scan lines) |
| R4 | 7 | W | Vertical total (char rows - 1) |
| R5 | 5 | W | Vertical total adjust (extra scan lines) |
| R6 | 7 | W | Vertical displayed (displayed char rows) |
| R7 | 7 | W | Vertical sync position |
| R8 | 6 | W | Interlace + display/cursor delays (see below) |
| R9 | 5 | W | Scan lines per character − 1 (− 2 in Interlace Sync & Video mode — MODE 7 only) |
| R10 | 7 | W | Cursor start scan line + blink/enable bits |
| R11 | 5 | W | Cursor end scan line |
| R12,R13 | 14 | W | Screen start address (DIV 8 for modes 0-6) |
| R14,R15 | 14 | R/W | Cursor position |
| R16,R17 | 14 | R | Light pen position (latched on LPSTB pulse) |
Per-mode register values (NAUG §13.3.3 p196; cross-checked against master-arm Ch 6)
| Reg | Mode 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| R0 Horizontal total | 127 | 127 | 127 | 127 | 63 | 63 | 63 | 63 |
| R1 Characters per line | 80 | 80 | 80 | 80 | 40 | 40 | 40 | 40 |
| R2 Horizontal sync pos | 98 | 98 | 98 | 98 | 49 | 49 | 49 | 51 |
| R3 Sync widths | &28 | &28 | &28 | &28 | &24 | &24 | &24 | &24 |
| R4 Vertical total | 38 | 38 | 38 | 30 | 38 | 38 | 30 | 30 |
| R5 Vertical total adjust | 0 | 0 | 0 | 2 | 0 | 0 | 2 | 2 |
| R6 Vertical displayed | 32 | 32 | 32 | 25 | 32 | 32 | 25 | 25 |
| R7 Vertical sync pos | 34 | 34 | 34 | 27 | 34 | 34 | 27 | 27 |
| R8 Interlace mode | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 3 |
| R8 Display delay (bits 4-5) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| R8 Cursor delay (bits 6-7) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 |
| R9 Scan lines per char-1 | 7 | 7 | 7 | 9 | 7 | 7 | 9 | 18 |
| R10 Cursor start | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 18 |
| R11 Cursor end | 8 | 8 | 8 | 9 | 8 | 8 | 9 | 19 |
R8 hex values shown reflect bits 0-1 (interlace), 4-5 (display delay), 6-7 (cursor delay) combined.
R8 — Interlace + delays
| Bits | Field |
|---|---|
| 0-1 | Interlace mode: 00/10=non-interlaced, 01=interlace sync, 11=interlace sync+video (MODE 7 only) |
| 4-5 | Display blanking delay: 00 none / 01 one char / 10 two chars / 11 disable video. MODE 7 needs 01 for saa5050 |
| 6-7 | Cursor blanking delay: same encoding; MODE 7 uses 10 |
Practical screen blank/unblank (used by raster splits and smooth-vertical-scroll): write &F0 to R8 to blank (display skew = 11 = non-display), &C0 to unblank with cursor off (display skew = 00, cursor skew = 11). The chip’s own DISPTMG gate is toggled, giving a clean transition with no mid-byte serialiser artefact. Mid-frame R8 skew rewrites are safe on the HD6845S despite the datasheet’s blanket “R8 prohibited” verdict — see crtc-6845-advanced.
R10 — Cursor start + blink
| Bits | Field |
|---|---|
| 0-4 | Cursor start scan line (CSL) |
| 6 | B — blink enable |
| 5 | P — blink period (or steady on/off when B=0) |
BP encoding (per Hitachi HD6845S datasheet Table 7 — hd6845sp-hitachi-datasheet):
| BP | Effect |
|---|---|
00 | Cursor steady on (non-blink) |
01 | Cursor off (non-display) |
10 | Blink with 16-field period (~3 Hz at 50 Hz — faster of the two) |
11 | Blink with 32-field period (~1.5 Hz — slower of the two) |
MOS default: BP = 10 (B-bit set, P-bit clear) → R10 = &47 in graphics modes (CSL=7), &52 in MODE 7 (CSL=18). This produces the BBC’s visible flashing underline cursor at ~3 Hz. The COPY (screen-edit) cursor uses BP = 11 for the slower blink.
⚠️ Contradicts BeebWiki’s CRTC page which describes the encoding as off/steady/slow/fast in a different order. Empirics (default flashing cursor) match the Hitachi datasheet, which is the primary source. See hd6845sp-hitachi-datasheet contradiction section.
Screen start (R12, R13) — the scrolling lever
R12 holds bits 8-13, R13 holds bits 0-7 of screen_address / 8. The divisor of 8 is because the address is in character-cell units of 8 scan lines.
Writing this register pair is the basis of all hardware scrolling — see hardware-scrolling.
Note: R12, R13 are write-only. To read the current screen start, use OSBYTE &A0 with X=&50 (returns &350/&351 from the OS workspace), not the chip.
MODE 7 — XOR &54 quirk
In MODE 7 the address translator interprets MA differently (Teletext path, with MA11=1, MA12=0 flagging Teletext addressing — see address-translation). To produce the right MA for screen RAM at &3C00-&3FFF or &7C00-&7FFF, MOS XORs the desired address with &54 before writing R12/R13. The address-translation page documents the full MODE 7 formula phys = ((MA & 0x800) << 3) | 0x3C00 | (MA & 0x3FF).
Practical conversion (for direct R12/R13 writes in MODE 7):
R12 = (high_byte_of_addr - &74) EOR &20
R13 = low_byte_of_addr
Same correction must be applied to R14/R15 (cursor position) in MODE 7. See hardware-scrolling.
Hardware wrap-around
When the 6845 fetches a video address ≥ &8000 (i.e. into ROM space), dedicated hardware subtracts a mode-dependent amount to bring the address back into screen RAM. The subtract amount is chosen by 2 bits on the System VIA addressable latch (IC 32) — see address-translation for the full mechanism (subtract amounts: &4000/&2000/&5000/&2800 for MODES 3/6/0-2/4-5) and system-via for the latch.
Chip variant — HD6845S required
The BBC uses the Hitachi HD68B45S specifically (2 MHz bus, 3.7 MHz CRT). Per hd6845sp-hitachi-datasheet the S variant adds six features over the R variant; the BBC exercises three of them critically:
- Programmable vertical sync pulse width (R3 high nibble) — HD6845R is fixed at 16 raster periods; HD6845S supports 1-16. BBC MOS uses VSW=2.
- Odd vertical character counts — HD6845R counts vertical chars in 2-line units (even-only); HD6845S counts in 1-line units. Required for
R6 = 25(MODES 3/6/7). - SKEW function in R8 (bits 4-7) — DISPTMG and CUDISP delay bits. Absent on HD6845R. Required for MODE 7 to align with the SAA 5050 character generator’s pipeline.
Plus three additional differences (less critical for BBC but worth knowing):
- R12/R13 readable on S (write-only on R).
- Cursor in Interlace Sync & Video mode: R shows in both fields; S shows in either even or odd field only.
- Reset signal: S releases MA/RA outputs asynchronously when /RES asserts; R waits for CLK low.
Programming restrictions
From the Hitachi datasheet — violations produce undefined behaviour, not errors:
0 < Nhd < Nht + 1 ≤ 256(horizontal displayed < horizontal total)0 < Nvd < Nvt + 1 ≤ 128(vertical displayed < vertical total)0 ≤ Nhsp ≤ Nht(hsync position within line)0 ≤ Nvsp ≤ Nvt(vsync position within frame)0 ≤ Ncstart ≤ Ncend ≤ Nr(cursor start ≤ end ≤ max raster) — except in Interlace Sync & Video mode whereNcend ≤ Nr + 12 ≤ Nr ≤ 30(Interlace Sync & Video only — MODE 7’s R9=18 fits)3 ≤ Nhtminimum (5 in non-interlace mode)- In interlace modes,
R0must be even (Nhtodd, soR0 = Nht − 1is even). MODE 7 (R8=3) has R0 = 63 — non-even — ⚠️ technically outside spec; works because HD6845S is forgiving. R3HSW low nibble =0is prohibited (undefined). VSW = 0 means 16 raster periods (special-case wraparound).
Light pen (R16, R17)
Latched on rising edge of LPSTB (pin from the analogue port). 14-bit value = address-at-time-of-strobe (in character units). Software must subtract a mode-dependent correction factor (§13.3.9 p197-198) — given for each mode:
| Mode | Correction |
|---|---|
| 0, 1, 2 | &0606 |
| 3 | &0806 |
| 4, 5 | &0B04 |
| 6 | &0C04 |
| 7 | &2808 |
Then y = (R16R17 - correction) DIV chars_per_line, x = (R16R17 - correction) MOD chars_per_line, scaled by displayed-vs-6845-chars ratio.
Worked light-pen IRQ handler is given on §13.3.9 p199 — hooked via IRQ2V at &206/&207, with the System VIA Interrupt Flag at &FE4D masked with &88 (light-pen bit + master IRQ bit).
Register latching (and which registers tolerate mid-frame writes)
The 6845 does not uniformly latch registers at frame boundaries — different registers behave differently when rewritten during display. Per the Hitachi datasheet’s “Anomalous Operations” table:
- R12/R13 (start address) are sampled during the last raster period of the field. Rewrites outside that window are safe. Writes during the last raster period give a “split start address” for one frame.
- R8 (interlace + skew) dynamic rewrite is prohibited by the datasheet — scan-mode bits and skew bits cannot be changed safely during display. Schedule R8 changes during reset or full reprogramming.
- R0, R2, R7, R9 rewrites during display WILL disturb the picture (NG per datasheet).
- R1, R6 rewrites are safe.
- R3, R4, R5, R10, R11 are conditional (safe in most of the line/raster; specific phase windows cause artefacts).
- R14/R15 (cursor position) should be rewritten during retrace; mid-display writes cause one frame of temporary glitch.
Full table on crtc-6845-advanced. The takeaway for raster-tight code: R12/R13 is the only major timing register you can freely rewrite mid-frame — fortunately the most useful one for hardware scrolling.
NAUG §13.3.12 p203 attributes flicker in BASIC hardware-scroll examples to mid-frame writes; the underlying mechanism is the two-write R12-then-R13 protocol straddling the last-raster sample window. If the sample happens between your two writes, the chip uses (new R12, old R13) for one frame.
Reset behaviour
/RES (active-low) clears all internal counters and forces all outputs low. Control registers are NOT affected by reset.
Quirks of the HD6845S reset:
/RESonly works while LPSTB is at logic-low. (BBC ties LPSTB to the analogue-port light-pen line — normally low.)- HD6845S starts display immediately after /RES release.
- First field after reset is anomalous: DISPTMG and CUDISP are not output (display inhibited), and the Start Address Register is ignored — MA and RA start at 0. From the second field onward, R12/R13 take effect.
This wiki is curated by Claude following the LLM-Wiki methodology — a human curates source documents, the LLM compiles structured cross-linked markdown. Content may contain errors, omissions, or stale claims. For authoritative information refer to the original source documents in the bbc-documents GitHub archive.