Epson 4X Sideways Copy

Developer(s): Keith Skapinski
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Printer

This program prints a 4× enlarged sideways screen copy to an Epson-compatible dot-matrix printer by scanning the TS2068 display using the POINT function and sending raw dot-matrix graphics commands via OUT to port 127. The BASIC version (lines 50–250) iterates over the 256×176 pixel display in groups of four columns, assembling a packed byte from four POINT tests that each contribute a 2-bit pattern (192, 48, 12, or 3) to encode pixel density for the printer’s bit-image mode. A companion machine code loader (the second program block) POKEs 674 bytes of Z80 object code starting at address 64676 for a compiled, faster version of the same routine, with execution via RANDOMIZE USR 64676. The printer handshaking subroutine at line 240 polls IN 127 for status values 109 or 237 before each byte is sent, implementing a hardware busy-wait loop. Several DATA lines contain placeholder “x” characters where numeric values appear to have been corrupted or omitted in the original listing.


Program Structure

The listing contains two independent programs. The first is a self-contained BASIC screen-dump routine (lines 50–250). The second is a machine code loader (lines 10–270) that POKEs a precompiled Z80 routine into high RAM and provides instructions for saving and running it. Both programs implement the same 4× sideways screen-dump function, with the loader version intended for faster execution after compilation or direct use via RANDOMIZE USR 64676.

BASIC Version — Printer Output Mechanism

Printer communication is handled entirely through OUT 127, sending bytes directly to the parallel port. Before every byte transmission, the subroutine at line 240 polls IN 127 in a busy-wait loop, only returning when the port value is 109 or 237 — the two possible “ready” states of the printer interface. This tight handshaking prevents buffer overruns on the Epson side.

The Epson initialization sequence at line 50 sends ESC “A” followed by byte 8, setting the line feed to 8/72 inch to match the dot pitch used in bit-image mode. Line 210 sends ESC “2” to restore the default line spacing, and line 220 issues an LPRINT (blank line) to advance the paper.

Screen Scanning and Pixel Encoding

The outer loop (line 60) steps i from 255 down to 0 in steps of −4, traversing the 256-pixel-wide display in column groups. For each group of four columns, the inner loop (line 90) steps j from 175 down to 0 — scanning each row of the display from bottom to top, producing the sideways orientation. For each row position, four POINT calls test pixels at i, i−1, i−2, and i−3, contributing 192, 48, 12, and 3 respectively to the accumulator t. These values are exact 2-bit shifts (192=0b11000000, 48=0b00110000, 12=0b00001100, 3=0b00000011), packing four 2-bit dot pairs into a single byte.

Each computed byte is sent twice (lines 150 and 170) to double the vertical dot density, achieving the 4× magnification in the print direction. Line 80 sets bit-image mode with OUT 127 sending ESC “K” followed by 96 and 1, specifying 352 dots (176×2) per line in single-density mode.

Machine Code Loader

The second program clears memory to address 64675 (CLEAR 64675) and then reads 20 DATA strings per iteration, concatenating them into d$. It then POKEs bytes from address 64676 to 65350 (674 bytes total), extracting each value as VAL d$(TO 4) and trimming the string with d$=d$(5 TO) — a standard technique for loading multi-byte machine code from space-padded decimal DATA strings.

Key BASIC Idioms

  • VAL d$(TO 4) with fixed-width 4-character fields efficiently extracts successive decimal values from a concatenated DATA string without additional parsing logic.
  • The busy-wait at line 240 using IF IN 127<>109 AND IN 127<>237 THEN GO TO 240 is a common idiom for parallel port synchronization.
  • The space-check at line 160 (IF INKEY$=" " THEN GO TO 250) provides a soft abort during the print loop.
  • Line 70 sends 12 space bytes before each column’s bit-image data as inter-column spacing to achieve the 4× width enlargement in combination with the double-send of each dot byte.

Notable Techniques

Packing four pixels into one byte using additive contributions of 192, 48, 12, and 3 is mathematically elegant: each pair of bits represents one screen pixel column scaled up 2× in the printer’s dot resolution. This avoids bit-shift operations, which are slow in interpreted BASIC, by using precomputed decimal constants instead.

The REM at line 40 of the BASIC version explicitly references compilation with TiMachine and suggests declaring i, j, and t as integers, which would substantially accelerate the innermost loop when compiled.

Machine Code Entry Points (Inferred)

AddressPurpose
64676Main entry point (RANDOMIZE USR 64676)
64676–65350674 bytes of Z80 object code

Source Code

   10 REM Epson 4X Sideways Copy
   20 REM By Keith Skapinski
   30 REM 
   40 REM -For best results,     compile with TiMachine. Use ...  "! INT i,j,t"
   50 OUT 127,27: GO SUB 240: OUT 127,CODE "A": GO SUB 240: OUT 127,8: GO SUB 240
   60 FOR i=255 TO 0 STEP -4
   70 FOR t=1 TO 12: OUT 127,32: GO SUB 240: NEXT t
   80 OUT 127,27: GO SUB 240: OUT 127,CODE "K": GO SUB 240: OUT 127,96: GO SUB 240: OUT 127,1: GO SUB 240
   90 FOR j=175 TO 0 STEP -1
  100 LET t=0
  110 IF POINT (i,j) THEN LET t=t+192
  120 IF POINT (i-1,j) THEN LET t=t+48
  130 IF POINT (i-2,j) THEN LET t=t+12
  140 IF POINT (i-3,j) THEN LET t=t+3
  150 OUT 127,t: GO SUB 240
  160 IF INKEY$=" " THEN GO TO 250
  170 OUT 127,t: GO SUB 240
  180 NEXT j
  190 OUT 127,10: GO SUB 240
  200 NEXT i
  210 OUT 127,27: GO SUB 240: OUT 127,CODE "2": GO SUB 240
  220 LPRINT 
  230 GO TO 250
  240 IF IN 127<>109 AND IN 127<>237 THEN GO TO 240
  245 RETURN 
  250 STOP 
   10 REM This is a loader pro-  gram for the machine code ver-  sion of 4Xsideway2. Run this    program and then SAVE "4Xsidecode"CODE 64676,674. To use RANDOMIZE USR 64676.
   20 REM This program appeared  in LISTing Newsletter of Long   Island written by Keith         Skapinski, Coram, N.Y. 11727     It's a great program!!!!
   30 CLEAR 64675
   40 LET d$="": FOR a=1 TO 20: READ a$: LET d$=d$+a$: NEXT a
   50 FOR a=64676 TO 65350
   60 POKE a,VAL d$( TO 4): LET d$=d$(5 TO ): NEXT a
   70 REM 
   80 DATA " 205  14 255  33  70 255  34 108  92  33 127   0 229  33  27   0 193 237 105 205 136 254  33 127   0 229  33  65   0 193 237 105 205 136"
   90 DATA " 254  33 127   0 229  33   8   0 193 237 105 205 136 254  33 255   0  34  70 255 229  33   0   x  34  76 255  33 252 255  34  78 255 203"
  100 DATA " 124 225 195  79 254  33   1   0  34  74 255 229  33  12   0  34  84 255 225 195  18 253  33 127   0 229  33  32   0 193 237 105 205 136"
  110 DATA " 254  42  74 255  35  34  74 255 237  91  84 255 235 167 237  82 226  32 253 124 238 128 242 254 252  33 127   0 229  33  27   0 193 237"
  120 DATA " 105 205 136 254  33 127   0 229  33  75   0 193 237 105 205 136 254  33 127   0 229  33  96   0 193 237 105 205 136 254  33 127   0 229"
  130 DATA "  33   1   0 193 237 105 205 136 254  33 175   0  34  72 255 229  33   0   0  34  80 255  33 255   x  34  82 255 203 124 225 195  34 254"
  140 DATA "  33   0   0  34  74 255  42  70 255 229  42  72 255 193  69 205  55 255 124 181 202 145 253  42  74 255  17 192   0  25  34  74 255  42"
  150 DATA "  70 255  43 229  42  72 255 193  69 205  55 255 124 181 202 173 253  42  74 255  17  48   0  25  34  74 255  42  70 255  43  43 229  42"
  160 DATA "  72 255 193  69 205  55 255 124 181 202 202 253  42  74 255  17  12   0  25  34  74 255  42  70 255  43   x   x 229  42  72 255 193  69"
  170 DATA " 205  55 255 124 181 202 231 253  42  74 255  35  35  35  34  74 255  33 127   0 229  42  74 255 193 237 105 205 136 254 205  24 255 205"
  180 DATA "   2 255   1   0  32 205 196 254 124 181 194 178 254 205  78  19  33 127   0 229  42  74 255 193 237 105 205 136 254  42  72 255 237  91"
  190 DATA "  82 255  25 203 122  34  72 255 237  91  80 255  32   1 235 167 237  82 226  50 254 124 238 128 242 112 253  33 127   0 229  33  10   0"
  200 DATA " 193 237 105 205 136 254  42  70 255 237  91  78 255  25 203 122  34  70 255 237  91  76 255  32   1 235 167 237  82 226  95 254 124 238"
  210 DATA " 128 242 237 252  33 127   0 229  33  27   0 193 237 105 205 136 254  33 127   0 229  33  50   0 193 237 105 205 136 254 205  19 255  62"
  220 DATA "  13 215 205  14 255 195 178 254  33 127   0  68  77 237 104  38   0  17 109   0 205 188 254 229  33 127   0  68  77 237 104  38   0  17"
  230 DATA " 237   0 205 188 254 124 181 209  40   1 235 124 181 194 136 254  33  22  43 217 201  33  22  43 217 201 175 237  82 103 111 200  44 201"
  240 DATA "  62   7  15 245 205 175  47 213 197 205 175  47 225 124 181 227 120  32  11 177 193  40   4 241  63  24  22 241  24  19 177  40  13  26"
  250 DATA " 150  56   9  32 237  11  19  35 227  43  24 223 193 241 167  33   0   0  48   1  44  15 216 125 238   1 111 201 225  78  35  70  35  84"
  260 DATA "  93   9 229 195 116  46  62   2 195  48  18  62   3 195  48  18 205 176   2  14   0  32  19 205  92   3  48  14  21  95 205 113   3 245"
  270 DATA "   1   x   0 247 241  18  14   1   6   0 195 116  46 205   3  38  71   4 126   7  16 253 230   1  38   0 111 201   0   x   x   x   x   x"

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