Display and LCD
The display subsystem turns text, graph buffers, menus, and equation layouts into the 96×64 monochrome image scanned from LCD-controller video RAM. This page maps the OS-facing render paths and software buffers; LCD controller and display bus reconstructs commands, addressing, timing, initialization, reads, power, and controller-revision behavior.
Display paths
The OS uses direct rendering for homescreen text and an explicit RAM back buffer for graphs. [confirmed]
flowchart LR
TEXT["text and menus"] --> PUT["_PutMap / _VPutMap"]
PUT --> LCD["controller video RAM"]
GRAPH["graph rasterizers"] --> BUF["plotSScreen · 0x9340"]
BUF --> CPY["_GrBufCpy"]
CPY --> LCD
LCD --> PANEL["96×64 panel"]
LCD --> SAVE["_SaveDisp → saveSScreen"]
SAVE --> RESTORE["_RestoreDisp"]
RESTORE --> LCD
| Path | Main entry | Behavior |
|---|---|---|
| Large text | _PutMap at 01:5A98 | draws one large-font glyph directly into controller RAM |
| Cooked character | _PutC at 01:5B4C | calls _PutMap, advances curCol, and handles newline/wrap |
| String | _PutS at 01:5C39 | emits a null-terminated large-font string |
| Small text | _VPutMap/_VPutS | renders variable-width glyphs using penCol/penRow |
| Graph clear | _GrBufClr at 04:6071 | clears 768 bytes of plotSScreen; does not touch the LCD |
| Graph blit | _GrBufCpy at 04:60A3 | copies selected graph-buffer rows to controller RAM |
| Physical clear | _ClrLCDFull at 01:60E4 | writes zero to all 768 visible controller bytes |
| Save/restore | _SaveDisp/_RestoreDisp | captures and restores the displayed image |
Software display state
| Address | Name | Size | Role |
|---|---|---|---|
0x8447 | contrast | 1 byte | OS contrast level used to build controller command 0xC0–0xFF |
0x844A | curTime | 1 byte | timer-driven cursor blink countdown |
0x844B/0x844C | curRow/curCol | 2 bytes | 16×8 homescreen character cursor |
0x845A–0x8461 | lFont_record | 8 bytes | current large-font render record |
0x8508–0x8587 | textShadow | 128 bytes | 16×8 homescreen character shadow |
0x86EC–0x89EB | saveSScreen | 768 bytes | saved display image |
0x9340–0x963F | plotSScreen | 768 bytes | graph/back buffer, 12 bytes × 64 rows |
Both 768-byte buffers use the MonoFramebuffer layout: [confirmed]
typedef struct {
uint8_t rows[64][12];
} MonoFramebuffer;
Each rows[y][byte_column] byte holds eight pixels, most-significant bit first.
Controller video RAM is a third image store outside Z80 RAM. Direct text output
can change it without changing plotSScreen, while graph drawing can change
plotSScreen without changing the panel until _GrBufCpy runs. [confirmed]
LCD-ready wait [confirmed]
_lcd_busy = 0x4051, body ram:0CC3, preserves AF while polling port
0x02 bit 1 until the LCD reports ready. If bit 3 of IY + 0x41 is set after
that poll, it calls the short delay helper at ram:0CE6 three times before
restoring AF and returning. The ROM has callers in the fixed page and on
pages 0x01, 0x04, 0x06, 0x07, 0x39, and 0x3B; it is the common
serialization point used before direct LCD operations.
A source-built fixture reaches the body and returns to its marker. That trace
confirms the callable path in TilEm, while the port-poll latency and optional
three-delay branch remain dependent on emulator or hardware LCD state. The
result is pinned in tools/data/community-manual-bcall-traces.csv.
Large-font text
_PutMap clamps character code zero and codes at or above 0xF8 to replacement code 0xD0. It computes character × 8 and bjumps to put_glyph_large at 07:4588. [confirmed]
The page-7 blitter adjusts that offset to a seven-byte packed stride:
$$ \text{glyph address} = \texttt{07:45FF} + 7c $$
where $c$ is the character code. It then copies eight bytes into lFont_record, so the eighth byte overlaps the first byte of the next packed glyph. [confirmed]
Two flags at IY+0x35 select alternate font-hook sources before the page-7 table read. Bit 5 calls 3B:7BFB with selector A=0x01; bit 1 calls 3B:7B9C with selector A=0x76. With neither flag set, _PutMap reads the built-in table. [confirmed]
The renderer positions the controller from curRow and curCol. Glyph edges use controller read-modify-write with the required dummy data read before the real byte. The complete bus sequence is in LCD controller and display bus.
Cursor and indicators
_CursorOn and _CursorOff reload curTime with 50. Standard hardware timer
1 reaches cursor_blink_tick at 06:7C45, which toggles the cursor every 50
ticks. See Clock, timers, and power.
[confirmed]
The run indicator uses indicCounter and indicBusy at 0x8476/0x8477. _RunIndicOn seeds it, and run_indicator_tick at ram:027B advances it from the same standard-timer interrupt. _ClrLCDFull temporarily clears and then restores the indicator-enable bit around the physical clear. [confirmed]
Numeric and string output
_DispHL at 01:5BF6 converts HL to five decimal positions with repeated _DivHLBy10, stores digits backward in scratch RAM, replaces leading zeroes with spaces, and prints through _PutC. [confirmed]
_PutC wraps when curCol reaches 16 and calls the newline/scroll path. _PutS and related bounded-string entries repeat _PutC over character data. These APIs target the character-oriented homescreen state, not the graph buffer. [confirmed]
Graph and equation rendering
Graph rasterizers write plotSScreen and call _GrBufCpy or _PDspGrph to expose the result. Coordinate transforms, clipping, line/circle algorithms, and graph state are covered in Graphing.
MathPrint uses a separate layout engine before its glyphs reach the display primitives. Its descriptors, box tree, cursor geometry, and runtime gaps are covered in Equation display.
The table editor and Y= screens build text-grid state through their own context handlers. See Table and Y= variables.
Related deep dives
- LCD controller and display bus — ports, status, commands, addressing, waits, initialization, clear/blit/read paths, contrast, power, dynamic I/O traces, and cross-emulator fidelity.
- Graphing — graph buffer, transforms, pixels, lines, circles, and graph display.
- Equation display — MathPrint layout and compositing.
- Table and Y= variables — table grid and function editor.