--- title: "Character" id: 55186 type: "computer_media" slug: "character" url: "http://localhost/computer_media/character/" markdown_url: "http://localhost/computer_media/character.md" published_at: "2024-06-20T11:49:56+00:00" modified_at: "2026-03-30T21:29:27+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/06/Character.png" excerpt: "Browse every character in the built-in font one by one, with each glyph's 8×8 pixel bitmap rendered live on screen using custom block graphics." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Utility" slug: "utility" taxonomy: "genre" url: "http://localhost/type/utility/" media_contents: - id: 55220 title: "Long Island Sinclair Timex (LIST) User Group Library Tape #7" type: "computer_media" url: "http://localhost/computer_media/long-island-sinclair-timex-list-user-group-library-tape-7/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Character%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/06/Character.png" media_type_tags: "Utility" --- # Character This program is a character set browser that displays each of the 96 printable ASCII characters (codes 32–127) along with a visual representation of the 8×8 pixel bitmap that defines each glyph. It reads the ROM character set address from system variables at addresses 23606–23607, then peeks the 8 bytes that define each character’s dot matrix. Each row byte is decomposed bit-by-bit using repeated integer division by 2, and each bit is rendered using a UDG (User Defined Graphic) character — either a filled or empty block depending on whether the bit is 1 or 0. A single UDG is defined at startup via the DATA statement at line 100, which encodes a fully bordered 8×8 square (255, 129, 129, 129, 129, 129, 129, 255). The program pauses between characters waiting for a keypress, then stops after displaying all 96 characters. *** ## Program Analysis ### Program Structure The program is organized into three logical phases: 1. **Initialization (lines 5–10):** Defines a single UDG and locates the ROM character set base address. 2. **Display loop (lines 15–65):** Iterates over all 96 printable characters (ASCII 32–127), displaying each glyph’s bitmap row by row with a keypress pause between entries. 3. **Data (line 100):** Provides the 8 bytes for the UDG used to render “off” pixels (a hollow bordered square). ### Character Set Address Lookup Line 10 reads the system variable pair at addresses 23606 and 23607, which together hold a pointer to the start of the character set data (normally pointing into ROM). The formula `PEEK 23606 + 256 * PEEK 23607 + 256` computes the 16-bit address and adds 256. This offset of 256 is necessary because the system variable actually points 256 bytes *before* the character data for CHR$ 32 (space), so adding 256 aligns `o` to the actual start of the space character’s bitmap. Each subsequent character occupies 8 consecutive bytes, accessed as `o + p + j*8` where `j` is the character index (0–95) and `p` is the row (0–7). ### Bit Extraction Technique Lines 35–50 implement a right-to-left bit unpacking loop without using bitwise operators. For each of the 8 bits in a byte, the code computes: - `x = INT(byte / 2)` — integer quotient (shifts right by one bit) - `bit = byte - 2*x` — the least significant bit (0 or 1) - `byte = x` — advance to next bit Because bits are extracted LSB-first but printed left-to-right with a decrementing column index (`AT p, 9-l`), the display ends up correctly oriented — bit 7 (MSB) appears at the leftmost column. ### UDG Usage Only one UDG is defined (character 144, `\a`), using the 8 bytes `255,129,129,129,129,129,129,255` — an 8×8 square outline. This represents an “off” pixel. An “on” pixel is rendered as `CHR$(144 - 1)` = `CHR$ 143`, which is the built-in block graphic character `\::=█` (a fully filled 8×8 block). The expression `CHR$(144 - bit)` thus elegantly selects between the filled block (when `bit=1`) and the UDG square outline (when `bit=0`). ### Display Layout For each character, the screen shows: - The character code and the character itself printed at row 4, column 20 (`AT 4,20`) - The decimal byte value for each of the 8 rows, printed at column 15 - The 8×1 pixel row rendered graphically starting at column 2 (columns 2–9), using `AT p, 9-l` ### Notable Idioms and Anomalies The `PAUSE 0` at line 60 waits indefinitely until any key is pressed — a standard keypress-wait idiom. The condition `IF j<>95` skips the pause after the final character (index 95, CHR$ 127), so the program simply halts with `STOP` at line 65 after the last entry. Line 9997 contains a redundant `STOP` that is unreachable under normal execution. Line 9998 is a `SAVE` statement that saves the program. ### Variable Summary | Variable | Purpose | | --- | --- | | `o` | Base address of character bitmap data in ROM | | `j` | Character index (0–95, corresponding to CHR$ 32–127) | | `p` | Row index within the 8×8 character bitmap (0–7) | | `byte` | Current bitmap row byte, consumed during bit extraction | | `l` | Bit position counter within a row (1–8) | | `x` | Temporary integer quotient during bit extraction | | `bit` | Extracted bit value (0 or 1) | | `a` | Temporary variable for reading UDG DATA bytes | ## Source Code ``` 5 RESTORE : FOR j=0 TO 7: READ a: POKE USR CHR$ 144+j,a: NEXT j 10 LET o=PEEK 23606+256*PEEK 23607+256 15 FOR j=0 TO 95: CLS : PRINT AT 4,20;"CHR$ ";j+32;" ";CHR$ (j+32) 20 FOR p=0 TO 7 25 LET byte=PEEK (o+p+j*8) 30 PRINT AT p,15;byte 35 FOR l=1 TO 8 40 LET x=INT (byte/2): LET bit=byte-2*x: LET byte=x 45 PRINT AT p,9-l;CHR$ (144-bit) 50 NEXT l 55 NEXT p 60 IF j<>95 THEN PRINT AT 15,0;"press any key for next character": PAUSE 0 65 NEXT j: STOP 100 DATA 255,129,129,129,129,129,129,255 9997 STOP 9998 SAVE "CHARACTER" LINE 0 ```