--- title: "Lprint" id: 56864 type: "computer_media" slug: "lprint-2" url: "http://localhost/computer_media/lprint-2/" markdown_url: "http://localhost/computer_media/lprint-2.md" published_at: "2024-09-29T12:26:03+00:00" modified_at: "2026-04-03T07:58:47+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/09/332_Lprt.png" excerpt: "A machine code printer driver copies a custom character set into RAM and patches it live before sending your typed text to the line printer." 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 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Demo" slug: "demo" taxonomy: "genre" url: "http://localhost/type/demo/" media_contents: - id: 56738 title: "Timex Sinclair Public Domain Library Tape 1007" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1007/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/09/332_Lprt.png" media_type_tags: "Demo" --- This program installs a custom character set into memory and uses it to send text to a line printer (LPRINT) via machine code. It copies 113 bytes of machine code from address 2161 into RAM at 31744, then patches two bytes (at 31800 and 31857) to customize the routine. The user enters a string of up to 32 characters; each character’s 8-byte bitmap is looked up from arrays U() or S() depending on whether it is a standard or graphics character (CODE > 127), then packed into a buffer at 32255. Finally, the character-code mapping table at 16444 is set to a sequential 0–31 identity map and the machine code routine is invoked via USR 31744. *** ## Program Analysis ### Program Structure The program has three distinct phases: machine code installation (lines 5–50), user input and character lookup (lines 505–700), and buffer preparation plus printer invocation (lines 9990–9999). 1. **Lines 5–50:** Switches to FAST mode, copies 113 bytes of machine code from ROM/RAM at address 2161 to 31744, then patches byte at 31800 to `63` and byte at 31857 to `201` (a Z80 `RET` instruction). 2. **Lines 505–520:** Returns to SLOW mode, prompts the user for a string to print. 3. **Lines 522–700:** Re-enters FAST mode; iterates over each character of the input string, populating a 32×8 array `A` with bitmap rows drawn from either array `U` (standard characters, CODE ≤ 127) or array `S` (graphics/special characters, CODE > 127, offset by 155). 4. **Lines 9990–9999:** Packs array `A` into a contiguous 256-byte buffer at 32255, writes an identity map (0–31) to the printer character table at 16444, calls the machine code via `USR 31744`, then loops back to line 500 (which does not exist — likely intended as 505, causing the program to restart the input prompt). ### Machine Code Usage The core printer driver is a 113-byte Z80 routine relocated from address 2161 (within the ZX81/TS1000 ROM or a previously loaded area) to 31744 in user RAM. Two bytes are patched after copying: | Address | Value | Likely Purpose | | --- | --- | --- | | 31800 | 63 | Operand patch (e.g. port number or jump offset) | | 31857 | 201 | Z80 `RET` instruction — terminates the routine | The routine is invoked at line 9998 with `USR 31744`; its return value is stored in `HPRINT` but is not subsequently used. The system variable area at 16444 (the printer buffer or character mapping table) is pre-loaded with an identity sequence 0–31 so the routine can index characters directly. ### Character Lookup Arrays The program relies on two pre-existing numeric arrays, `U` and `S`, which must have been loaded or defined before this program runs — they are not dimensioned or populated here. Array `U(code, row)` provides 8-row bitmaps for standard characters (CODE 0–127). Array `S(code-155, row)` provides bitmaps for graphics characters whose CODE exceeds 127, with the offset of 155 normalising the index. ### Output Buffer Layout The 32-character × 8-row bitmap is packed sequentially into memory starting at address 32255. The POKE at line 9992 computes the target address as `32255 + K + 8*(J-1)`, placing character `J`‘s row `K` at successive bytes. This produces a 256-byte block (32 chars × 8 bytes) laid out in character-major, row-minor order, which the machine code routine then streams to the printer port. ### Key BASIC Idioms and Techniques - `FAST`/`SLOW` switching is used carefully: FAST during memory-intensive POKE loops, SLOW during user-facing PRINT/INPUT. - `DIM A(32,8)` at line 525 allocates a fresh 2D array each time the input loop runs, effectively clearing any previous character data. - The space character is handled by a short-circuit `GOTO 700` at line 540, leaving the corresponding row in `A` as all zeros (blank bitmap). - Line 9999 performs `GOTO 500` targeting a non-existent line; execution will fall through to line 505, restarting the input prompt — a deliberate loop-back technique. ### Bugs and Anomalies - The `DIM A(32,8)` statement is inside what becomes an effective loop (lines 505–9999 repeat), so the array is re-dimensioned on every pass. On a ZX81/TS1000 this is legal and clears the array, but it wastes time re-allocating memory on each iteration. - Array `U` is indexed as `U(CODE X$(X), Y)`, but `CODE` of a printable character starts at 28 (space) on the ZX81. If `U` is not large enough to accommodate these indices, an out-of-bounds error will occur. - The buffer at 32255 spans addresses 32255–32510, which overlaps with the top of available RAM on a 1 KB machine; a 16 KB RAM pack is implicitly required. - `LET HPRINT=USR 31744` stores the machine code’s return value but it is never read, making the assignment redundant. ## Source Code ``` 1 SAVE "1033%2" 5 FAST 10 FOR I=0 TO 112 20 POKE 31744+I,PEEK (2161+I) 30 NEXT I 40 POKE 31800,63 50 POKE 31857,201 505 SLOW 510 PRINT "ENTER TEXT TO BE LPRINTED USING NEW CHARACTER SET:" 520 INPUT X$ 522 FAST 525 DIM A(32,8) 530 FOR X=1 TO LEN X$ 540 IF X$(X)=" " THEN GOTO 700 550 IF CODE X$(X)>127 THEN GOTO 600 560 FOR Y=1 TO 8 570 LET A(X,Y)=U(CODE X$(X),Y) 580 NEXT Y 590 GOTO 700 600 FOR Y=1 TO 8 610 LET A(X,Y)=S(CODE X$(X)-155,Y) 620 NEXT Y 700 NEXT X 9990 FOR J=1 TO 32 9991 FOR K=1 TO 8 9992 POKE 32255+K+8*(J-1),A(J,K) 9993 NEXT K 9994 NEXT J 9995 FOR H=0 TO 31 9996 POKE 16444+H,H 9997 NEXT H 9998 LET HPRINT=USR 31744 9999 GOTO 500 ```