This program demonstrates “pixelprint,” a machine code routine that renders text strings at arbitrary pixel coordinates on the screen rather than being constrained to the fixed character grid. The BASIC loader at line 9001 loads the machine code block into memory starting at address 40960 (decimal) and sets up a GOSUB-callable interface at line 9000, which passes parameters via POKEs to consecutive bytes at that address. Characters are rendered using two UDG slots (“T” and “U”) as intermediate buffers, splitting each 8×8 character into four quadrants before printing with OVER 1 to allow precise sub-character positioning. Variables p and q specify the pixel-coordinate top-left corner of the first character, while xdisp and ydisp control inter-character displacement, enabling effects like diagonal or scrolling text as demonstrated in line 9005. The program saves itself in two parts: the BASIC demonstration as “PixelPrnt” with an auto-run line, and the 395-byte machine code block as “PixelprntC” at address 40960.
Program Analysis
Program Structure
The listing is a self-contained demonstration and save utility for a machine code character renderer. It splits into four logical sections:
- Lines 9000: The BASIC wrapper (GOSUB target) that POKEs parameters into the machine code’s variable area and calls
RANDOMIZE USR 40976in a loop over each character ofs$. - Lines 9001–9003: Loader and introductory screen — loads the CODE block, sets up paper/ink, and displays usage documentation.
- Lines 9004–9005: Demonstration routines showing pixel-positioned strings, including a two-pass “I am not a crook!” example and an animated scrolling “BEWARE THE IDES OF MARCH” sequence.
- Lines 9006–9998: Comments, technical documentation, and the SAVE/CLEAR commands to package the program for distribution.
Machine Code Interface
The machine code block resides at address 40960 (0xA000). The first 16 bytes act as a parameter block, with each byte mapped to a named variable:
| Address (hex) | BASIC variable | Purpose |
|---|---|---|
| A000 | p | X pixel coordinate of first character |
| A001 | q | Y pixel coordinate of first character |
| A002 | xdisp | Horizontal displacement between characters |
| A003 | ydisp | Vertical displacement between characters |
| A004 | s$(i) | Character code for current glyph |
| A005 | row | Internal: computed row |
| A006 | col | Internal: computed column |
| A007 | p’ | Internal: working x |
| A008 | q’ | Internal: working y |
| A009 | dp | Internal: x pixel offset within cell |
| A00A | dq | Internal: y pixel offset within cell |
| A00B | 8-dp | Internal: complement of dp |
| A00C | 8-dq | Internal: complement of dq |
| A00D | address of graphic | Pointer into ROM font data |
The actual entry point called by BASIC is at address 40976 (0xA010), 16 bytes past the start of the block, leaving the first 16 bytes as the parameter/variable scratchpad. The total machine code block is 395 bytes (SAVE "PixelprntC" CODE 40960,395).
Rendering Technique
The routine uses UDG characters “T” and “U” as a two-cell working buffer. Each 8×8 source glyph is split into four quadrants based on the sub-character pixel offsets dp and dq. The quadrant data is composed into UDGs “T” and “U,” which are then PRINTed with OVER 1 at the appropriate character-grid position. Because OVER 1 XORs pixels, any previously rendered content must be erased by a second pass (explaining the repeated GO SUB pix calls in line 9005 before moving to the next string).
Key BASIC Idioms
- Symbolic GOSUB target via variable:
LET pix=9000followed byGO SUB pixmakes the subroutine address easily relocatable without editing every call site. - Per-character loop at GOSUB level: Line 9000 iterates
FOR i=1 TO LEN s$, POKEingCODE s$(i)and invoking the machine code for each character individually, keeping the machine code routine simple (single-character input). - PAUSE 0 before INKEY$ pattern: Line 9003 uses
PAUSE 0as an efficient keypress wait before clearing the lower screen prompt. - Double-GOSUB erase pattern: In line 9005, each string is rendered twice (once to draw, once to erase with OVER 1 XOR) before the next string is placed, producing a simple animation effect.
Demonstration Sequences
Line 9004 demonstrates sub-character offset rendering: “I am not a crook!” is printed at pixel (75,67), then again at (65,63) with ydisp=-2, creating a slight diagonal repetition. Line 9005 animates “BEWARE THE IDES OF MARCH” by scrolling upward (ydisp=-8, xdisp=0), printing each word and erasing it before moving to the next, all starting from pixel column 0.
Save Structure
Line 9998 uses CLEAR before saving, which resets the RAMTOP and clears variables. Two files are saved:
"PixelPrnt"— the BASIC program withLINE 9001auto-run."PixelprntC"— raw CODE at address 40960, length 395 bytes.
Line 9001 loads "PixelprntC" from tape before the demonstration begins, making the pair a self-bootstrapping distribution package.
Copyright Notice
A \* (©) symbol and “1984 Cameron Hayne” appear in the REM at the end of line 9000, embedding a machine-readable copyright notice directly in the source.
Content
Source Code
9000 POKE 40960,p: POKE 40961,q: POKE 40962,xdisp: POKE 40963,ydisp: FOR i=1 TO LEN s$: POKE 40964,CODE s$(i): RANDOMIZE USR 40976: NEXT i: RETURN : REM \* 1984 Cameron Hayne
9001 CLS : PRINT AT 10,1;"Leave recorder running"," data now loading": LOAD "PixelprntC"CODE : BEEP .7,4: PAPER 7: INK 0: CLS : LET pix=9000
9002 PRINT AT 0,0;"pixelprint enables you to print a string "; INK 2;"s$"; INK 0;" starting at pixel position "; INK 2;"(p,q)"; INK 0;". Here p is the x coordinate of the top left corner of the imaginary 8 x 8 square which will enclose the first character of s$. Similarlyq is the y coordinate."' INK 2;"xdisp "; INK 0;"is the displacement "'"between characters in the x "'"direction (normally 8)."'"Similarly "; INK 2;"ydisp"; INK 0;" (normally 0)"'" Example of use:"
9003 PRINT #1;AT 0,0;"PRESS ANY KEY": PAUSE 0: PRINT #1;AT 0,0;" "
9004 LET s$="I am not a crook!": LET p=75: LET q=67: LET xdisp=8: LET ydisp=0: GO SUB pix: LET p=65: LET q=63: LET ydisp=-2: GO SUB pix
9005 PAUSE 40: LET xdisp=0: LET ydisp=-8: LET s$="BEWARE": LET p=0: LET q=60: GO SUB pix: PAUSE 5: GO SUB pix: LET s$="THE": GO SUB pix: PAUSE 5: GO SUB pix: LET s$="IDES": GO SUB pix: PAUSE 5: GO SUB pix: LET s$="OF": GO SUB pix: PAUSE 5: GO SUB pix: LET s$="MARCH": GO SUB pix: PAUSE 5: GO SUB pix
9006 STOP : REM Technical info:pixelprint uses user defined graphics "T" and "U". The character is divided up into 4 parts- the top two are put into "T","U"then printed, then the bottom two. The printing is done with OVER 1 ,so anything already on the screen must first be erased
9007 REM m/c variables: A000,p A001,q A002,xdisp A003,ydisp A004,s$(i) A005,row A006,col A007,p' A008,q' A009,dp A00A,dq A00B,8-dp A00C,8-dq A00D,address of graphic
9998 CLEAR : SAVE "PixelPrnt" LINE 9001: BEEP .4,15: SAVE "PixelprntC"CODE 40960,395
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
