--- title: "“BOLD” Character Subroutine" id: 56281 type: "computer_media" slug: "boldsub" url: "http://localhost/computer_media/boldsub/" markdown_url: "http://localhost/computer_media/boldsub.md" published_at: "2024-08-04T10:49:46+00:00" modified_at: "2026-04-03T07:59:05+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/08/SCR-20240803-hkaw.png" excerpt: "A two-author machine code hack from 1985 that rewrites the system font in RAM to produce genuinely bold characters — toggled on or off at runtime with a single POKE." 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/" indiv: - name: "Frank Bouldin (W5GAA)" slug: "frank-bouldin" taxonomy: "indiv" url: "http://localhost/indiv/frank-bouldin/" genre: - name: "Font" slug: "font" taxonomy: "genre" url: "http://localhost/type/font/" media_contents: - id: 56277 title: "Timex Sinclair Public Domain Library Tape 2001" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2001/" - id: 60550 title: "Fort Worth TS2068 Club Library Tape" type: "computer_media" url: "http://localhost/computer_media/fort-worth-ts2068-club-library-tape/" media_type: "Program" programmers: - name: "Frank Bouldin (W5GAA)" slug: "frank-bouldin" taxonomy: "indiv" url: "http://localhost/indiv/frank-bouldin/" download_url: "https://archive.org/download/timex-sinclair-software-archive/BoldSub%20%281985%29%28Bouldin%2C%20Frank%3B%20Jackson%2C%20Ben%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1985" images: - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240803-hkaw.png" media_type_tags: "Font" --- # “BOLD” Character Subroutine This program implements a “BOLD” character display routine for the TS2068 by patching the system font pointer at address 23607. A 80-byte machine code routine is loaded via DATA statements into RAM at address 63900 and executed with RANDOMIZE USR 63900; it copies and modifies the character set to RAM starting at address 64000 (FA00 hex), ORing pixel pairs together to create a bold effect. The user is prompted whether to activate bold characters, and the routine switches between the modified font (POKE 23607,250) and the standard ROM font (POKE 23607,60) accordingly. The demonstration prints a full alphanumeric sample string using FLASH and waits for a keypress before looping. *** ## Program Analysis ### Program Structure The listing divides into three logical sections: 1. **Lines 10–60:** Documentation REMs, a demonstration loop that prints a sample alphabet and sentence, and a FLASH prompt to repeat. 2. **Lines 9000–9080:** The “BOLD” subroutine proper — machine code loader (9020–9030) and the interactive bold-on/off prompt (9040–9070). 3. **Lines 9500–9530:** DATA statements holding the 80 bytes of Z80 machine code. Line 9999 performs a `CLEAR` and saves the program with auto-run from line 1 (which falls through to `GO SUB 9000` at line 45 via the absence of an explicit line 1, so execution starts at the lowest line, line 10, and reaches line 45). ### Machine Code Loader Line 9020 uses `RESTORE 9500` followed by a `FOR`/`READ`/`POKE` loop to deposit 80 bytes into addresses 63900–63979. Line 9030 then calls this code with `RANDOMIZE USR 63900`. The target area (F9DC–FA27 hex) sits well above the normal BASIC/variable area and is below the UDG region, making it a safe scratch space on a stock TS2068. ### Z80 Machine Code Disassembly Reconstructing the DATA bytes (63900 onward): | Offset | Bytes | Mnemonic | Notes | | --- | --- | --- | --- | | 0 | 42 54 92 | LD HL,(5C54h) | Load CHARS system variable (font base pointer − 256) | | 3 | 17 00 FA | … DE = FA00h | Destination buffer at 64000 | | 6 | 01 00 04 | LD BC,0400h | Copy 1024 bytes (256 chars × 4 bytes used) | | … | … | Inner loop | Reads source byte, ORs with shifted copies to fatten strokes, stores to destination | | … | 201 | RET | Return to BASIC | The repeated pattern `230,N … 203,2xx` corresponds to `AND N` / `SET b,(HL)` sequences that test individual pixel columns and set the adjacent column, effectively expanding each lit pixel one position to the right to produce boldness. The final bytes `62,0,18,19,35,11,120,177,32,186,201` handle the loop counter decrement (`DEC BC`; test `B|C`) and the `RET`. ### Font Switching Mechanism The TS2068 (like the ZX Spectrum) uses the system variable `CHARS` at address 23607 (5C57h) to point to the character set base minus 256. The standard ROM font lives at address 15616 (3D00h), so `CHARS` normally holds 60 (3Ch). After the machine code copies and boldifies the font into RAM at FA00h, `POKE 23607,250` (FAh) redirects `CHARS` to the new bold font at FA00h. Restoring normal characters requires only `POKE 23607,60`. ### Interactive Prompt (Lines 9040–9070) The subroutine prints a yes/no question and polls `INKEY$` in a tight loop (lines 9050–9070). Both upper- and lower-case Y and N are accepted. This is a straightforward busy-wait rather than using `PAUSE 0`, meaning the CPU spins continuously until a key is detected. ### Demonstration Loop (Lines 50–60) Line 50 prints a comprehensive sample string covering all letters (upper and lower case), digits, and punctuation at fixed `AT` positions. Line 60 uses `FLASH 1` for the repeat prompt, then `PAUSE 0` to wait for any keypress, `CLS`, `GO SUB 9040` to re-query bold preference, and `GO TO 50` to loop. This means the bold/normal choice can be changed on every cycle. ### Notable Techniques - Storing machine code above address 63900 keeps it safely outside the BASIC program area without requiring a `CLEAR` to reserve RAM (the `CLEAR` on line 9999 is only in the SAVE statement). - Using `RESTORE 9500` before the load loop ensures the DATA pointer is reset correctly even if the subroutine is called more than once. - `VAL` is not used here; line numbers are literal, which is consistent with the program’s educational/demonstration intent. - The DATA is split across multiple lines (9500, 9510, 9520, 9530) with intervening REM lines (9505, 9515, 9525) purely for readability; the REMs are skipped by the sequential `READ`. ### Potential Issues - The machine code copies only 1024 bytes (`BC = 0400h`), covering characters 32–159 (128 chars × 8 bytes). If the full 768-byte standard set (96 printable chars) or UDGs are needed, the count may need adjustment depending on exact implementation. - Line 9999 calls `CLEAR` immediately before `SAVE`; when the saved program is later loaded and run, `CLEAR` is not re-executed before the machine code is poked in, which is correct — but users who issue `CLEAR` manually with a high address could overwrite the code buffer at 63900. - The busy-wait loop at lines 9050–9070 does not include a `PAUSE`, so it will consume all CPU time while waiting for input. ## Source Code ``` 10 REM "BOLD" Character sub- routine 20 REM by F. Bouldin & Ben Jackson (7-12-85) 30 REM Near beginning of yourprogram before any print state- ments add statement "GOSUB 9000"then add subroutine below (lines9000-9530). 40 REM Example: 42 REM 45 GO SUB 9000 50 PRINT AT 10,2;"TIMEX-SINCLAIR 2068 Computer";AT 12,6;"---sample fonts---";AT 14,0;"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890.,*/?`:©;)('&%$#@!......Now is thetime for all good men to come tothe aid of their country!" 55 REM note required statement"GOSUB 9040" in line 60 for thisexample. 60 PRINT FLASH 1;AT 10,2;AT 21,2;" Press any key to repeat ": PAUSE 0: CLS : GO SUB 9040: GO TO 50 7000 REM 8000 REM 9000 REM "BOLD" character sub- routine 9010 REM Machine code routine 9020 RESTORE 9500: FOR I=63900 TO 63979: READ A: POKE I,A: NEXT I 9030 RANDOMIZE USR 63900 9040 PRINT AT 11,0;"""BOLD"" characters desired?...Y/N" 9050 IF INKEY$="Y" OR INKEY$="y" THEN POKE 23607,250: CLS : RETURN 9060 IF INKEY$="N" OR INKEY$="n" THEN POKE 23607,60: CLS : RETURN 9070 GO TO 9050 9080 REM 9500 DATA 42,54,92,17,0,250,1,0,4,126,18,230,3,32,4,126,203,207 9505 REM 9510 DATA 18,126,230,7,32,4,126,203,215,18,126,230,15,32,4,126 9515 REM 9520 DATA 203,223,18,126,230,31,32,4,126,203,231,18,126,230,63,32,4,126,203,239,18,126,254,66,32 9525 REM 9530 DATA 4,126,203,239,18,126,254,0,32,3,62,0,18,19,35,11,120,177,32,186,201 9999 CLEAR : SAVE "BOLD" LINE 1 ```