--- title: "Italics" id: 56300 type: "computer_media" slug: "italics" url: "http://localhost/computer_media/italics/" markdown_url: "http://localhost/computer_media/italics.md" published_at: "2024-08-04T10:49:54+00:00" modified_at: "2026-03-30T21:43:21+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-jghd.png" excerpt: "A self-contained machine code generator shifts every ROM character right to fake italics, then saves the 768-byte result as a relocatable font you can drop into any program." 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_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Italics%20%28198x%29%28Stagnell%2C%20Ben%29%28TS2068%29%28UK%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-jghd.png" media_type_tags: "Font" --- This program installs a custom italic character set for use in BASIC programs by POKEing 42 bytes of Z80 machine code into address 30000, then executing it with RANDOMIZE USR. The machine code (lines 30–40) copies and transforms the ROM character set from address 15616 (0x3D00) to address 30208 (0x7600), applying two right-rotation operations (RLC→RRC, i.e. CB 63 twice) to each byte to produce an italic slant effect. The resulting 768-byte block (three pages covering 96 characters) is then saved to tape as a named CODE file. After saving, the user redirects the system font pointer via POKEs to addresses 23606 and 23607 (CHARS system variable) in their own program to activate the italic set at any load address. *** ## Program Analysis ### Program Structure The program is a one-shot utility that builds, executes, and saves a machine-code font transformer. Its flow is strictly linear: 1. Lines 1–5: REM documentation block explaining usage and the CHARS system variable POKEs. 2. Line 20: `LIST` — displays the program listing so the user can read the instructions before anything runs. 3. Line 30: Loads 42 bytes of Z80 machine code into RAM at address 30000. 4. Line 40: The `DATA` statement containing those 42 bytes. 5. Line 50: `RANDOMIZE USR 30000` — calls the machine code routine. 6. Lines 60–80: Asks for a filename, then saves the generated font block. 7. Lines 90–100: Rewind prompt and `VERIFY`. 8. Lines 110–120: Completion beep and `NEW` to clean up. ### Machine Code Routine (address 30000) The 42 data bytes disassemble to a Z80 routine that copies the ROM character set and applies a bit-rotation to each byte to produce an italic effect: | Offset | Bytes (hex) | Mnemonic | Notes | | --- | --- | --- | --- | | 0 | 21 00 3D | LD HL,3D00h | Source: ROM charset (char 32 = space) | | 3 | 11 00 76 | LD DE,7600h | Destination: 30208 decimal | | 6 | 01 00 03 | LD BC,0300h | 768 bytes = 96 characters × 8 rows | | 9 | ED B0 | LDIR | Block copy ROM font to RAM | | 11 | 21 00 76 | LD HL,7600h | Point to start of copied font | | 14 | 0E 60 | LD C,60h | Outer loop: 96 characters | | 16 | 06 02 | LD B,02h | Inner loop A: 2 rows per pass (top portion) | | 18 | 7E | LD A,(HL) | Load byte | | 19 | CB 3F | SRL A | Shift right logical (italic slant) | | 21 | CB 3F | SRL A | Second right shift | | 23 | 77 | LD (HL),A | Write back | | 24 | 23 | INC HL | Next row | | 25 | 10 F7 | DJNZ 18 | Loop B times | | 27 | 06 04 | LD B,04h | Inner loop B: 4 rows (middle) | | 29 | 7E | LD A,(HL) | Load byte | | 30 | CB 3F | SRL A | Single right shift | | 32 | 77 | LD (HL),A | Write back | | 33 | 23 | INC HL | Next row | | 34 | 10 F9 | DJNZ 29 | Loop B times | | 36 | 23 | INC HL | Skip remaining 2 rows (bottom = unshifted) | | 37 | 23 | INC HL | | | 38 | 0D | DEC C | Decrement character counter | | 39 | C8 | RET Z | Return when all 96 chars processed | | 40 | 18 E6 | JR 14 | Loop back to outer character loop | The italic effect is achieved by dividing each 8-row character bitmap into three zones: the top 2 rows are shifted right by 2 bits (`SRL` twice), the middle 4 rows by 1 bit, and the bottom 2 rows are left unchanged. This creates a stepped rightward lean that mimics italic slant when rendered on screen. ### Font Relocation and the CHARS System Variable The generated font is saved as a raw CODE block of 768 bytes starting at 30208 (0x7600). To use it, the host program must update the `CHARS` system variable at addresses 23606–23607, which normally points 256 bytes before the ROM font. The REM in line 5 gives the correct formula: - `POKE 23606, addr - 256*INT(addr/256)` — low byte of (addr − 256) - `POKE 23607, INT(addr/256)` — high byte Because `CHARS` is indexed from character 0 (not character 32), the system subtracts 256 bytes (32 chars × 8 rows) from the supplied address, so the caller must account for this offset. ### Key BASIC Idioms and Notable Techniques - `LINE N$` in the `INPUT` statement (line 60) accepts the full input as a string without string-quote processing, allowing filenames with spaces or special characters. - `RANDOMIZE USR 30000` is the standard idiom for calling machine code; the return value from the routine (0 from `RET Z`) is discarded harmlessly. - `NEW` at line 120 clears both the BASIC program and variables after saving, leaving a clean slate — appropriate for a utility intended to run exactly once. - The `LIST` at line 20 serves as an in-program documentation display, ensuring the user reads the REM instructions before any code executes. ### Anomalies and Observations - The outer loop counter in C is loaded as 0x60 (96), covering the printable ASCII range (characters 32–127), which matches the 768-byte save length exactly. - The bottom 2 rows of each character are skipped entirely (two `INC HL` instructions), so descenders and baseline pixels are not shifted — this preserves legibility at the cost of a slight discontinuity at the character baseline. - The routine does not preserve registers, but since it is called via `USR` and returns with `RET Z` after the loop naturally exhausts, this is benign. ## Source Code ``` 1 REM "CHAR SET2" 2 REM 'ITALICS' 3 REM By Ben Stagnell 4 REM ZX Computing Monthly 5 REM To use in any memory addr CLEAR addr-1, LOAD "code name" CODE addr, play tape then type or include as pgm lines POKE 23606,addr -256*INT (addr/256): POKE 23607,INT (addr/256) Where "addr" is any address you wish to put the code at. 20 LIST 30 FOR N=30000 TO 30041: READ A: POKE N,A: NEXT N 40 DATA 33,0,61,17,0,118,1,0,3,237,176,33,0,118,14,96,6,2,126,203,63,203,63,119,35,16,247,6,4,126,203,63,119,35,16,249,35,35,13,200,24,230 50 RANDOMIZE USR 30000 60 INPUT "NAME TO SAVE >) "; LINE N$ 70 CLS : PRINT "SAVING :";N$ 80 SAVE N$CODE 30208,768 90 PRINT ''"REWIND TAPE TO VERIFY" 100 VERIFY N$CODE 110 BEEP .1,10: PRINT "SAVE COMPLETE" 120 NEW ```