Double Thick Characters

Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Font

This program generates and saves a “double thickness” character set replacement for the system font. It works by POKEing 30 bytes of Z80 machine code into memory at address 30000, then executing it via RANDOMIZE USR 30000 to process the existing character ROM data and produce a double-thickness version of each character glyph at address 30208 (768 bytes covers the 96 printable characters at 8 bytes each). The generated code block can then be relocated to any address by updating the two system variables at 23606–23607, which together form the 16-bit pointer to the user-defined character set. The program finishes by prompting for a tape name, saving the 768-byte code block, verifying it, and issuing NEW to clean up.


Program Analysis

Program Structure

The program is a one-shot utility that follows a strict linear sequence:

  1. Lines 1–5: Documentation REMs explaining usage and relocation.
  2. Line 20: LIST — displays the listing so the user can read the instructions before running.
  3. Line 30–40: Loads 30 bytes of Z80 machine code into addresses 30000–30029 via a FOR/READ/POKE/NEXT loop.
  4. Line 50: Executes the machine code with RANDOMIZE USR 30000.
  5. Lines 60–80: Prompts for a tape name and saves the resulting 768-byte block at address 30208.
  6. Lines 90–110: Rewind prompt, VERIFY, confirmation beep.
  7. Line 120: NEW clears the BASIC workspace.

Machine Code Analysis

The 30 DATA bytes disassemble to a Z80 routine that reads the original ROM character data and writes a “double thickness” (bold) version into RAM. The bytes are:

AddressBytesMnemonicNotes
3000033,0,61LD HL,15616Source: start of ROM character set (address 0x3D00)
3000317,0,118LD DE,30208Destination: output buffer (0x7600)
300061,0,3LD BC,768768 bytes = 96 chars × 8 bytes
30009237,176LDIRCopy original font to RAM first
3001133,0,118LD HL,30208Now process the RAM copy in place
3001417,0,3LD DE,768Counter (reused as loop limit via register pair)
30017126LD A,(HL)Load one font byte
3001879LD C,ASave original
30019203,63SRL AShift right by 1
30021177OR COR with original — each set bit spreads one pixel right
30022119LD (HL),AWrite back double-thickness byte
3002335INC HLAdvance pointer
3002427DEC DEDecrement counter
30025122LD A,DTest if DE=0
30026179OR ED OR E = 0 only when DE exhausted
30027200RET ZReturn when all 768 bytes processed
3002824,243JR -13Loop back to 30017

The bold effect is achieved by ORing each byte with itself shifted one bit to the right (SRL A then OR C). This causes every lit pixel to also illuminate the pixel immediately to its right, producing a horizontally thickened glyph without any ROM patching.

Memory Layout

  • 15616 (0x3D00): ROM character set start — 768 bytes of standard 6×8 font data.
  • 3000030029: Temporary machine code buffer (30 bytes).
  • 30208 (0x7600): Output buffer for the generated bold font (768 bytes = 30208–30975).
  • System variables 2360623607: Low/high bytes of the user-defined character set pointer, updated manually post-load as described in the REM.

Key BASIC Idioms

  • FOR N=30000 TO 30029: READ A: POKE N,A: NEXT N — the standard single-line DATA loader idiom, keeping the code compact.
  • RANDOMIZE USR 30000 — calls machine code without requiring a function return value; any returned value is silently discarded as the seed.
  • INPUT "" LINE N$ — uses LINE to accept the full string including spaces without needing quotes, avoiding the default tokenisation of INPUT.
  • PRINT ' (apostrophe in PRINT) — emits a newline before the following string, providing spacing without a separate PRINT statement.

Notable Techniques

The two-phase approach — first LDIR copying the ROM font into writable RAM, then processing it in-place — is necessary because the ROM is not writable. The loop termination using LD A,D / OR E / RET Z is a classic Z80 idiom for testing a 16-bit counter for zero without consuming a register pair for a dedicated DJNZ-style counter, and avoids the overhead of a CP instruction on a 16-bit value.

The LIST on line 20 is an intentional design choice: since the usage instructions are embedded in the REM on line 5, running the program immediately displays the listing before proceeding, ensuring the user reads the relocation instructions prior to the machine code executing.

Potential Issues

  • The machine code and output buffer both reside in the same RAM region (around address 30000). The code occupies 30000–30029 and the output starts at 30208, so there is a 178-byte gap — no overlap occurs.
  • No CLEAR is issued in the program itself; the REM instructions tell the end-user to issue CLEAR addr-1 before loading the saved code block into a target address, which is essential to prevent BASIC heap corruption.
  • The right-shift bold algorithm can cause pixel bleed across character boundaries if a glyph has a set bit in column 8 (bit 0 after the shift) — however, the standard ROM font reserves the rightmost column as blank padding, so this is not a practical concern.

Content

Appears On

One of a series of library tapes. Programs on these tapes were renamed to a number series. This tape contained

Related Products

Related Articles

Related Content

Image Gallery

Source Code

    1 REM "CHAR SET1"
    2 REM 'DOUBLE THICKNESS'
    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 30029: READ A: POKE N,A: NEXT N
   40 DATA 33,0,61,17,0,118,1,0,3,237,176,33,0,118,17,0,3,126,79,203,63,177,119,35,27,122,179,200,24,243
   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 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

People

No people associated with this content.

Scroll to Top