--- title: "New Chars" id: 56244 type: "computer_media" slug: "new-chars" url: "http://localhost/computer_media/new-chars/" markdown_url: "http://localhost/computer_media/new-chars.md" published_at: "2024-07-22T01:26:03+00:00" modified_at: "2026-03-30T21:44:18+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/07/SCR-20240721-snwj.png" excerpt: "A compact loader patches two system variables to install a custom character set from a saved code block — here's how it redirects the UDG pointer at runtime." 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: "Font" slug: "font" taxonomy: "genre" url: "http://localhost/type/font/" media_contents: - id: 56205 title: "CATS Library Tape 11" type: "computer_media" url: "http://localhost/computer_media/cats-library-tape-11/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/New%20Chars%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240721-snwj.png" media_type_tags: "Font" --- This program prints a comprehensive character and keyword reference string, then loads a custom character set into memory and patches the system variable that points to the UDG (User Defined Graphics) table. The LOAD command at line 9991 brings in 520 bytes of machine code to address 64368, which is in the high RAM area typically used for custom data on the TS2068. Lines 9992 POKEs 23606 and 23607 to redirect the UDG pointer: the 16-bit address stored there is 250×256+112 = 64112, pointing the system to the newly loaded character definitions. Line 9998 saves both the BASIC loader and the machine code block, with LINE 9991 ensuring the code auto-runs on load. *** ## Program Analysis ### Program Structure The program has two functional sections: a single display line followed by a cluster of utility lines at the top of the line-number space. Line `1` is a print statement serving as a character/keyword reference. Lines `9989`–`9998` form the loader/installer for a custom character set stored as a machine code block. 1. **Line 1** — Prints a long reference string covering printable ASCII characters, TS2068 BASIC keywords, and special symbols. 2. **Lines 9989–9990** — REM comments labelling the purpose of the code block (“CHARACTERS A THRU Z”, “NEW CHR$ a”). 3. **Line 9991** — Loads 520 bytes of machine code to address 64368. 4. **Line 9992** — POKEs the UDG system variable to redirect it to the loaded character data. 5. **Line 9997** — STOP, preventing fall-through to the SAVE line during normal execution. 6. **Line 9998** — Saves the BASIC program (auto-running at line 9991) and the code block. ### Memory Map and System Variables The loader targets two well-known system variables to redirect the UDG character table: | Address | System Variable | Value POKEd | Purpose | | --- | --- | --- | --- | | 23606 | UDG (low byte) | 112 | Low byte of new UDG base address | | 23607 | UDG (high byte) | 250 | High byte of new UDG base address | The combined 16-bit address is `250 × 256 + 112 = 64112`. This places the new UDG table in high RAM, well above the normal RAMTOP area, consistent with the code block loaded at 64368 — the 520 bytes likely include both the character bitmaps and possibly a small machine code routine. ### The Code Block The block at address 64368 is 520 bytes long. Since standard UDG coverage for 26 lowercase letters (a–z) requires 26 × 8 = 208 bytes, the additional bytes (312 extra) suggest the block contains either extended character definitions, additional symbol glyphs, or supporting machine code. The REM at line 9989 references “A THRU Z”, confirming at minimum a full lowercase alphabet replacement. ### Key BASIC Idioms and Techniques - **High line numbers for utilities** — Placing the loader at lines 9989–9998 keeps it well away from any program content that would follow line 1, and makes it easy to identify as infrastructure rather than application code. - **STOP before SAVE** — Line 9997’s `STOP` prevents line 9998 from executing during normal program runs; the SAVE line is only intended to be run manually or during development. - **Auto-run SAVE** — `SAVE "NEW CHR$" LINE 9991` encodes the entry point so reloading the tape automatically runs the installer from line 9991. - **Paired SAVE commands** — The BASIC and CODE blocks are saved as two separate tape files under the same name, a standard technique for bundling a loader with its associated binary. ### Line 1 — Character Reference The PRINT statement on line 1 appears to be a developer reference listing every printable character alongside BASIC keywords, used to visually verify that the custom character set renders all glyphs correctly. It covers digits, uppercase and lowercase letters, punctuation, and a broad selection of TS2068 keywords including `BEEP`, `CIRCLE`, `SCREEN$`, `ATTR`, `STICK`, `ON ERR`, `FREE`, `SOUND`, and trigonometric/mathematical functions. ### Notable Observations - The UDG pointer (23606/23607) is set to 64112, which is 256 bytes *below* the loaded code block at 64368 — suggesting the character bitmap data begins at 64112 and the code (if any) follows it. - 520 bytes ÷ 8 bytes per character = 65 characters, enough to redefine the full UDG set (21 standard UDGs = 168 bytes) plus substantial additional data, or to cover a different range of characters entirely. - No error trapping (`ON ERR`) is used; if the LOAD at 9991 fails, execution halts with a tape error rather than gracefully recovering. ## Source Code ``` 1 PRINT "1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm!@#$%&'()_;AT OR AND ><>=<><= STOP NOT STEP TO THEN ^-+=.,*/?`:ASN ACS ATN VERIFY RND MERGE []IN OUT ©FREE STICK\\ON ERRBEEP CIRCLE VAL$ SCREEN$ ATTR BEEP INK PAPER FLASH BRIGHT OVER INVERSE SIN COS TAN INT RNDSTR$ CHR$ CODE PEEK TAB READ RESTORE DATA SGN ABS SQR VAL LEN USR LN EXP LPRINT LLIST BIN INKEY$PI" 9989 REM CHARAECTERS *A THRU Z* 9990 REM *********************** NEW CHR$ a *********************** 9991 LOAD "NEW CHR$"CODE 64368,520 9992 POKE 23606,112: POKE 23607,250 9997 STOP 9998 SAVE "NEW CHR$" LINE 9991: SAVE "NEW CHR$"CODE 64368,520 ```