64 Column Utility

Developer(s): Stan Lemke
Date: 1986
Type: Program
Platform(s): TS 2068

This program is a 64-column print utility that uses an external machine code routine (loaded from tape at address 57000, 2671 bytes long) to enable 64-character-wide mode. Text is entered by the user one character at a time, stored in a large 20,000-byte string array `a$`, and passed to the machine code via POKEs to addresses 57039 and 57041 before calling specific entry points (57077 for display file rendering, 57090/57104 for type-input handling, 57131 for a clear/reset routine, and 58000 for copy/print). Pages are 1,408 characters each, allowing the array to hold approximately 14 pages of text. The utility supports typing new text, loading existing data from tape, displaying it on screen, copying to printer, and saving the text buffer back to tape as a raw CODE block.


Program Analysis

Program Structure

The program is organized into a set of short subroutines at low line numbers (10–90), a type-input loop (100–160), a display-file section (300–310), a main initialization block (9000–9060), and a save/master-copy line (9999). The listing appears three times in the source, which is a formatting artifact of the submission — the program itself is a single unit.

LinesRole
20Display-file subroutine: renders stored text via machine code
40Type subroutine A: passes character to machine code entry point 57090
50Type subroutine B: passes character to machine code entry point 57104
60Initializes machine code page parameters (column offset 0, width 64)
70CLS then calls machine code clear/reset at 57131
90Clears the lower status bar (stream #0, row 0)
100–160Interactive text-entry loop, one character at a time
300–310Display/review loop, page by page
9000–9060Startup: dimensions array, loads machine code, sets colors, menu
9999Development save line: saves BASIC and machine code to tape

Machine Code Interface

The heart of the utility is a 2,671-byte machine code block loaded at address 57000. BASIC communicates with it entirely through POKEs to a small parameter area before each RANDOMIZE USR call:

  • POKE 57039, CODE a$(i)+1 — writes the character code (incremented by 1, likely converting to an internal token/index) for display rendering
  • POKE 57041, CODE a$(i+1) — writes the second character of a pair for the display-file path
  • POKE 57043, 0 and POKE 57044, 64 — set the column offset and line width for the 64-column mode

The machine code exposes at least five distinct entry points:

AddressPurpose
57000Main initialization routine
57077Display-file character renderer (processes pairs from a$)
57090Type-mode handler, first character in a pair
57104Type-mode handler, second character in a pair
57131Screen/printer clear or reset
58000Copy/print trigger

The OUT 255,54 at line 9040 is a hardware port write, likely controlling a printer interface or related peripheral to set it into 64-column mode.

Text Storage and Paging

Text is held in a$, dimensioned to 20,000 characters. A page is exactly 1,408 characters (64 columns × 22 rows, the printable area). Characters are stored in pairs and processed two at a time by the display loop at line 20, which iterates FOR i=c1 TO c2 STEP 2. The variable c1 advances by 1,408 on each new page, so up to approximately 14 pages can be stored in the array without reloading.

Machine Code Address Recovery

Line 9005 contains a notable technique for recovering the load address of the machine code block after it has been loaded from tape. Since LOAD ""CODE without an explicit address uses the address stored in the tape header, the code reads system variables 23629/23630 (the last LOAD address, sometimes called PROG or a related pointer) via PEEK and reconstructs the 16-bit address into j:

POKE 56998, PEEK 23629 : POKE 56999, PEEK 23630 : LET j = 256*PEEK 56999 + PEEK 56998

This value j is then used both as the base address for subsequent LOAD ""CODE j calls (line 9030) and as the start address for SAVE "64c"CODE j,i+1 (line 135).

Key BASIC Idioms

  • VAL "number" in GO TO/GO SUB: Used extensively throughout to encode branch targets as string literals, saving tokenized number storage bytes in the BASIC line.
  • PAUSE 0: LET b$=INKEY$: Standard efficient keypress-wait pattern appearing at lines 110, 120, 130, 305.
  • LET a$(1)=a$(1) at line 9005: A dummy self-assignment used to force the interpreter to allocate and fix the DIM’d string array in memory before its address is captured.
  • Stream #0 for status messages: All user-facing prompts are written to the lower screen via PRINT #0;AT ..., keeping the main display area undisturbed.

Notable Anomalies

  • Line 9010 contains a typo: "Pleae press 2" instead of "Please press 2".
  • The © keyword (RESET) appears in the REM header (line 3) as part of the author attribution layout, not as executable code.
  • Line 135 saves CODE j, i+1 — the length i+1 reflects the current character count, making each save a variable-length snapshot of typed content.
  • The display loop at line 310 advances c2 by adding 1407 to the new c1 (LET c2=c1+1407), which is correct for a 1,408-character page (indices c1 to c1+1407 inclusive).

Content

Appears On

Related Products

Related Articles

And now, here are a few more words about the last contest. First, we would like to thank all of...

Related Content

Image Gallery

64 Column Utility

Source Code

    1 REM ***********************
    2 REM 64 Column Print Utility
    3 REM RESET    by S D Lemke
    4 REM    2144 White Oak
    5 REM    Wichita, Ks 67207
    6 REM ***********************
   10 REM        Display File 
   20 FOR i=c1 TO c2 STEP 2: POKE 57039,(CODE a$(i)+1): POKE 57041,CODE a$(i+1): RANDOMIZE USR 57077: NEXT i: RETURN 
   30 REM             Type 
   40 POKE 57039,CODE b$+1: RANDOMIZE USR 57090: RETURN 
   50 POKE 57039,CODE b$+1: RANDOMIZE USR 57104: RETURN 
   60 POKE VAL "57043",VAL "0": POKE VAL "57044",VAL "64": RETURN 
   70 CLS : RANDOMIZE USR VAL "57131": RETURN 
   90 PRINT #0;AT 0,0;"                                                               ": RETURN 
  100 PRINT #0;AT 1,10;"TYPE INPUT"
  110 PAUSE 0: LET b$=INKEY$: GO SUB 40: LET i=i+1: LET a$(c1+i)=b$
  120 PAUSE 0: LET b$=INKEY$: GO SUB 50: LET i=i+1: LET a$(c1+i)=b$: IF i<=1408 THEN GO TO 110
  130 PRINT #0;AT 0,0;"Press N for Next Page, S to Save  C to Copy, D to Display File": FOR k=1 TO 20: NEXT k: PAUSE 0: LET b$=INKEY$: GO SUB VAL "90"
  135 IF b$="S" OR b$="s" THEN SAVE "64c"CODE j,i+1: GO TO VAL "130"
  140 IF b$="C" OR b$="c" THEN PRINT #0;AT 0,0;TAB 31;" ";';TAB 31;" ": RANDOMIZE USR VAL "58000": GO TO VAL "130"
  145 IF b$="D" OR b$="d" THEN GO SUB VAL "60": CLS : RANDOMIZE USR VAL "57131": GO TO VAL "300"
  150 GO SUB VAL "70": LET c1=1408+c1
  160 GO SUB VAL "60": GO TO VAL "100"
  300 LET c1=VAL "1": LET c2=VAL "1408": GO SUB VAL "60": GO SUB VAL "70"
  305 GO SUB VAL "20": PRINT #0;AT 0,8;"Press any key.": PRINT #0;AT 1,7;"Press C to Copy": PAUSE 0: IF INKEY$="C" OR INKEY$="c" THEN GO SUB VAL "90": RANDOMIZE USR VAL "58000"
  310 GO SUB VAL "70": LET c1=c1+1408: LET c2=c1+1407: GO SUB VAL "60": GO TO VAL "305"
 9000 DIM a$(20000): LOAD ""CODE : PAPER VAL "1": BORDER VAL "1": INK VAL "7": CLS 
 9005 LET i=VAL "0": LET c1=VAL "0": GO SUB VAL "60": LET a$(1)=a$(1): POKE VAL "56998",PEEK VAL "23629": POKE VAL "56999",PEEK VAL "23630": LET j=VAL "256"*PEEK VAL "56999"+PEEK VAL "56998"
 9010 CLS : PRINT AT VAL "2",VAL "4";"64 Column Print Utility": PRINT AT VAL "10",VAL "0";"Press 1 to type a page";';"      2 to load & display a file                                                                    Pleae press 2 to load an       explanation of this utility       and the demo program."
 9020 PAUSE VAL "0": LET b$=INKEY$: IF b$="1" OR b$="2" THEN GO TO VAL "9030"
 9025 GO TO VAL "9020"
 9030 IF b$="2" THEN PRINT AT 14,10;"START TAPE";AT 18,0;" ": LOAD ""CODE j
 9040 RANDOMIZE USR VAL "57000": OUT 255,54: CLS : RANDOMIZE USR VAL "57131"
 9050 IF b$="1" THEN GO TO VAL "100"
 9060 GO TO VAL "300"
 9999 CLEAR : SAVE "64c" LINE 9000: SAVE "64c"CODE 57000,2671
    1 REM ***********************
    2 REM 64 Column Print Utility
    3 REM RESET    by S D Lemke
    4 REM    2144 White Oak
    5 REM    Wichita, Ks 67207
    6 REM ***********************
   10 REM        Display File 
   20 FOR i=c1 TO c2 STEP 2: POKE 57039,(CODE a$(i)+1): POKE 57041,CODE a$(i+1): RANDOMIZE USR 57077: NEXT i: RETURN 
   30 REM             Type 
   40 POKE 57039,CODE b$+1: RANDOMIZE USR 57090: RETURN 
   50 POKE 57039,CODE b$+1: RANDOMIZE USR 57104: RETURN 
   60 POKE VAL "57043",VAL "0": POKE VAL "57044",VAL "64": RETURN 
   70 CLS : RANDOMIZE USR VAL "57131": RETURN 
   90 PRINT #0;AT 0,0;"                                                               ": RETURN 
  100 PRINT #0;AT 1,10;"TYPE INPUT"
  110 PAUSE 0: LET b$=INKEY$: GO SUB 40: LET i=i+1: LET a$(c1+i)=b$
  120 PAUSE 0: LET b$=INKEY$: GO SUB 50: LET i=i+1: LET a$(c1+i)=b$: IF i<=1408 THEN GO TO 110
  130 PRINT #0;AT 0,0;"Press N for Next Page, S to Save  C to Copy, D to Display File": FOR k=1 TO 20: NEXT k: PAUSE 0: LET b$=INKEY$: GO SUB VAL "90"
  135 IF b$="S" OR b$="s" THEN SAVE "64c"CODE j,i+1: GO TO VAL "130"
  140 IF b$="C" OR b$="c" THEN PRINT #0;AT 0,0;TAB 31;" ";';TAB 31;" ": RANDOMIZE USR VAL "58000": GO TO VAL "130"
  145 IF b$="D" OR b$="d" THEN GO SUB VAL "60": CLS : RANDOMIZE USR VAL "57131": GO TO VAL "300"
  150 GO SUB VAL "70": LET c1=1408+c1
  160 GO SUB VAL "60": GO TO VAL "100"
  300 LET c1=VAL "1": LET c2=VAL "1408": GO SUB VAL "60": GO SUB VAL "70"
  305 GO SUB VAL "20": PRINT #0;AT 0,8;"Press any key.": PRINT #0;AT 1,7;"Press C to Copy": PAUSE 0: IF INKEY$="C" OR INKEY$="c" THEN GO SUB VAL "90": RANDOMIZE USR VAL "58000"
  310 GO SUB VAL "70": LET c1=c1+1408: LET c2=c1+1407: GO SUB VAL "60": GO TO VAL "305"
 9000 DIM a$(20000): LOAD ""CODE : PAPER VAL "1": BORDER VAL "1": INK VAL "7": CLS 
 9005 LET i=VAL "0": LET c1=VAL "0": GO SUB VAL "60": LET a$(1)=a$(1): POKE VAL "56998",PEEK VAL "23629": POKE VAL "56999",PEEK VAL "23630": LET j=VAL "256"*PEEK VAL "56999"+PEEK VAL "56998"
 9010 CLS : PRINT AT VAL "2",VAL "4";"64 Column Print Utility": PRINT AT VAL "10",VAL "0";"Press 1 to type a page";';"      2 to load & display a file                                                                    Pleae press 2 to load an       explanation of this utility       and the demo program."
 9020 PAUSE VAL "0": LET b$=INKEY$: IF b$="1" OR b$="2" THEN GO TO VAL "9030"
 9025 GO TO VAL "9020"
 9030 IF b$="2" THEN PRINT AT 14,10;"START TAPE";AT 18,0;" ": LOAD ""CODE j
 9040 RANDOMIZE USR VAL "57000": OUT 255,54: CLS : RANDOMIZE USR VAL "57131"
 9050 IF b$="1" THEN GO TO VAL "100"
 9060 GO TO VAL "300"
 9999 CLEAR : SAVE "64c" LINE 9000: SAVE "64c"CODE 57000,2671
    1 REM ***********************
    2 REM 64 Column Print Utility
    3 REM RESET    by S D Lemke
    4 REM    2144 White Oak
    5 REM    Wichita, Ks 67207
    6 REM ***********************
   10 REM        Display File 
   20 FOR i=c1 TO c2 STEP 2: POKE 57039,(CODE a$(i)+1): POKE 57041,CODE a$(i+1): RANDOMIZE USR 57077: NEXT i: RETURN 
   30 REM             Type 
   40 POKE 57039,CODE b$+1: RANDOMIZE USR 57090: RETURN 
   50 POKE 57039,CODE b$+1: RANDOMIZE USR 57104: RETURN 
   60 POKE VAL "57043",VAL "0": POKE VAL "57044",VAL "64": RETURN 
   70 CLS : RANDOMIZE USR VAL "57131": RETURN 
   90 PRINT #0;AT 0,0;"                                                               ": RETURN 
  100 PRINT #0;AT 1,10;"TYPE INPUT"
  110 PAUSE 0: LET b$=INKEY$: GO SUB 40: LET i=i+1: LET a$(c1+i)=b$
  120 PAUSE 0: LET b$=INKEY$: GO SUB 50: LET i=i+1: LET a$(c1+i)=b$: IF i<=1408 THEN GO TO 110
  130 PRINT #0;AT 0,0;"Press N for Next Page, S to Save  C to Copy, D to Display File": FOR k=1 TO 20: NEXT k: PAUSE 0: LET b$=INKEY$: GO SUB VAL "90"
  135 IF b$="S" OR b$="s" THEN SAVE "64c"CODE j,i+1: GO TO VAL "130"
  140 IF b$="C" OR b$="c" THEN PRINT #0;AT 0,0;TAB 31;" ";';TAB 31;" ": RANDOMIZE USR VAL "58000": GO TO VAL "130"
  145 IF b$="D" OR b$="d" THEN GO SUB VAL "60": CLS : RANDOMIZE USR VAL "57131": GO TO VAL "300"
  150 GO SUB VAL "70": LET c1=1408+c1
  160 GO SUB VAL "60": GO TO VAL "100"
  300 LET c1=VAL "1": LET c2=VAL "1408": GO SUB VAL "60": GO SUB VAL "70"
  305 GO SUB VAL "20": PRINT #0;AT 0,8;"Press any key.": PRINT #0;AT 1,7;"Press C to Copy": PAUSE 0: IF INKEY$="C" OR INKEY$="c" THEN GO SUB VAL "90": RANDOMIZE USR VAL "58000"
  310 GO SUB VAL "70": LET c1=c1+1408: LET c2=c1+1407: GO SUB VAL "60": GO TO VAL "305"
 9000 DIM a$(20000): LOAD ""CODE : PAPER VAL "1": BORDER VAL "1": INK VAL "7": CLS 
 9005 LET i=VAL "0": LET c1=VAL "0": GO SUB VAL "60": LET a$(1)=a$(1): POKE VAL "56998",PEEK VAL "23629": POKE VAL "56999",PEEK VAL "23630": LET j=VAL "256"*PEEK VAL "56999"+PEEK VAL "56998"
 9010 CLS : PRINT AT VAL "2",VAL "4";"64 Column Print Utility": PRINT AT VAL "10",VAL "0";"Press 1 to type a page";';"      2 to load & display a file                                                                    Pleae press 2 to load an       explanation of this utility       and the demo program."
 9020 PAUSE VAL "0": LET b$=INKEY$: IF b$="1" OR b$="2" THEN GO TO VAL "9030"
 9025 GO TO VAL "9020"
 9030 IF b$="2" THEN PRINT AT 14,10;"START TAPE";AT 18,0;" ": LOAD ""CODE j
 9040 RANDOMIZE USR VAL "57000": OUT 255,54: CLS : RANDOMIZE USR VAL "57131"
 9050 IF b$="1" THEN GO TO VAL "100"
 9060 GO TO VAL "300"
 9999 CLEAR : SAVE "64c" LINE 9000: SAVE "64c"CODE 57000,2671

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

Scroll to Top