08 — Display & LCD
Deep dives: Graphing (graph buffer → LCD, transforms) · Table & Y= Variables (text grid).
The TI-84+ shows a 96×64 monochrome image — the OS only ever drives a 96×64 region (_ClrLCDFull clears all 768 bytes of it: 8 row-passes × 12 columns × 8 data bytes). The underlying controller (Toshiba T6K04 / later Novatek) has wider video RAM (up to 128 px), so 96×64 is the visible area, not the controller’s geometry. It is reached through I/O ports 0x10 (command) and 0x11 (data). The OS keeps a graph/screen buffer in RAM and renders text via a built-in font.
Controller [confirmed against code]
port_lcdCmd(0x10): commands — set row, set column, set Y, on/off, contrast.port_lcdData(0x11): read/write a byte of pixels at the current address.- The panel is organized in 8-pixel-tall rows;
_ClrLCDFull(01:60E4) loadsA=0xB8, subtracts8each pass and stops at0x80→ row commands0xB8 … 0x80(8 rows of 8 px = 64 px tall), calling_ClearRowper row with interrupts masked (DI). [confirmed] - Command bytes (all grounded in
_ClrLCDFull/_ClearRow/lcd_set_col_cmd):- Row (page) select =
0xB8 − 8·rowforrow = 0…7(i.e.0xB8, 0xB0, … 0x80), sent to0x10vialcd_set_col_cmd(01:5A89), which only emits the byte when0x80 ≤ A < 0xC0(guards the row/Z-address range)._ClrLCDFullwalks this by loadingA=0xB8, calling_ClearRow, thenSUB 0x8and looping whileA ≥ 0x80(B=0x80). - Column select =
0x20 + col, sent raw to0x10._ClearRow(01:6934) walksEfrom0x20to0x2B(CP 0x2Cterminates) = 12 columns (12 bytes × 8 px = 96 px wide), writing 8 data bytes to0x11per column — theB=0x08innerdjnzloop writes one byte per pixel row (8 rows). [confirmed] - Contrast:
lcd_set_contrast(01:5A59) writes the contrast level to the data port0x11;lcd_get_contrast(01:5A60) reads it back from the controller withIN A,(0x11)(the standard dummy+real LCD read), not a command re-send. The level is also held in RAM atcontrast(0x8447); the command-port form(contrast+0x18)|0xC0is what_LCD_DRIVERON(page 06) and the_GetKeycontrast keys send to0x10. [confirmed] - Every port access is preceded by
CALL ram:0CC3(lcd_wait), the controller-busy delay. [confirmed]
- Row (page) select =
Text output [confirmed]
curRow/curCol(0x844B/844C) — the homescreen text cursor (16 columns wide;_PutCwraps at col 16, calls_NewLine)._PutMap(01:5A98) draws one large-font character at the cursor: it clamps invalid codes to0xD0, computes an initialchar * 8offset, then bjumps to the page-7 large-font blitter, which adjusts that offset to the actual7-byte-strideglyph table before copying an 8-byte render record. [confirmed]_PutC(01:5B4C) =_PutMap+ advance cursor + newline handling;_PutSprints a string;_NewLinescrolls._DispHL(01:5BF6) printsHLas a right-justified 5-digit decimal: repeated_DivHLBy10, digits +0x30, leading zeros → spaces, writing the digits backward from0x847Cinto theOP1scratch area, then_PutC/_PutMapeach digit. [confirmed]
Screen buffers [standard]
plotSScreen(0x9340, 768 bytes = 96×64/8) — the main graph/back buffer.saveSScreen(0x86EC, 768 bytes) — saved copy (e.g. for menus over the graph)._GrBufCpy(04:60A3) blitsplotSScreento the LCD;_GrBufClr(04:6071) zero-fills the 768-byte graph buffer (LD HL,0x9340; LD (HL),0; LDIR) and does not touch the LCD.
Fonts [confirmed]
- Large font: glyph table is on page 7, base
07:45FF, with a7-byte strideper glyph (not 8)._PutMap(01:5A98) clamps the code (0or≥0xF8→0xD0), computesHL = char*8(threeADD HL,HL), then bjumps via trampolineram:3B3Dto the blitterput_glyph_large(07:4588). The blitter doesHL = 07:45FF + char*8, thenlgfont_glyph_ptr_adjust(07:45EB) subtractschar(it shiftschar*8right by 3 →char, thenSBC HL,DE), yielding the real glyph pointer07:45FF + char*7. It then copies an 8-byte record via_Mov8B(ram:1A94, 8×LDI) into RAM at0x845A(lFont_record), which the renderer blits. [confirmed] (The stride is 7 bytes while the copy is 8 bytes — the 8th byte overlaps the next glyph’s first row — so the table packs glyphs at07:45FF + char*7.) - Alternate large fonts: two bits in
(IY+0x35)select a replacement glyph source before the page-7 table read — bit 5 loadsA=0x01and callsram:36E7(bjump to3B:7BFB), bit 1 loadsA=0x76and callsram:3E1F(bjump to3B:7B9C); both are font-hook routines on page3Bthat take theAvalue as a selector. When neither bit is set, the page-7 table at07:45FFis used. [confirmed] - Small/variable-width font:
_VPutMap/_VPutS(graph screen, pixel-addressed viapenCol/penRow).
Indicators
flags.indicFlagsbit 0 = the run/busy indicator (the moving dashes top-right);_ClrLCDFullpreserves it across a clear;_RunIndicOn/_RunIndicOfftoggle it. [confirmed]
LCD command bytes and glyph table
- LCD command bytes confirmed by tracing
_ClrLCDFull(01:60E4),_ClearRow(01:6934) andlcd_set_col_cmd(01:5A89): row (page) select =0xB8 − 8·row(range0xB8 … 0x80, stepping down by 8), column select =0x20 + col(range0x20 … 0x2B, 12 columns = 96 px), command port0x10/ data port0x11, busy-wait viaram:0CC3. Contrast is held at RAMcontrast(0x8447) and written to the data port0x11bylcd_set_contrast(01:5A59). See Controller. [confirmed] - Large-font glyph table pinned: page
0x07, base07:45FF,7-byte stride(put_glyph_large@07:4588→ glyph ptr07:45FF + char*7via07:45EB, then_Mov8Bcopies an 8-byte record to RAM0x845A). See Fonts and Flash Page Map. [confirmed]