A 2068 Printer Driver

Author(s): P. H. Skipper
Publication: SyncWare News
Pub Details: SyncWare News v5 n2 (Volume 5, Issue 2)
Date: November/December 1987
Pages: 17-21

In reply to the request from Mr. George Cary in the May/June SyncWare News for a big printer driver for the Spectrum mode 2068, the accompaning machine-code program is submitted.

When supplemented by BASIC drivers as appropriate for the 2068 or the Spectrum and if POKEd as indicated below, this printer driver contains the following features:

  • It is located in high memory, below the UDG’s, and below the area that the Spectrum uses as a temporary store when NEWed. Thus, once installed, it will not be interfered with except by machine code which overwrites it.
  • It is not relocatable (except by being rewritten).
  • It works, without modification, with either the Aerco or the Tasman Centronics interfaces.
  • It can be POKEd to work with either the 2068 or the Spectrum.
  • It includes a screen copier as well as an LPRINT capability.
  • It does not include an LLIST capability.
  • It includes Tom Woods‘ “up-arrow” trick for sending Hex codes to the printer. (I.e. enter an up-arrow in the text followed by the desired two-character Hex code. To print an up-arrow, enter an up arrow in the text followed by another up-arrow.)
  • It can easily be POKEd to include the necessary codes used by various printers to implement their graphics modes.
  • It provides a small or a large screen copy.
  • It allows a choice of the left margin when copying the screen, thus permitting the small screen copy to be located horizontally on the page as desired.
  • It is modular. The LPRINT section can be used alone or just accompanied by the “up-arrow” section.

BASIC Drivers:

Figure 1 shows an example of a BASIC driver for this machine code when used with the 2068. Figure 2 shows one for the Spectrum. Of course, this BASIC code can be incorporated in one’s own program, also.

Figure 1. BASIC Program for 2068 Print Driver.

   1 LOAD "2a&tcy↑hi8"CODE 64815,384: STOP
2 POKE 26703,0: POKE 26704,5: STOP : REM 2040 Printer
3 POKE 26703,34: POKE 26704,254: STOP : REM SPIRIT-80 Printer
4 POKE 65057,0: RANDOMIZE USR 64815: STOP : REM Small-screen COPY
5 POKE 65057,1: RANDOMIZE USR 64815: STOP : REM Large-screen COPY

Figure 2. BASIC Program for SPECTRUM Print Driver.

   1 LOAD "5a&tcy↑hi8"CODE 64815,384: STOP
2 POKE 23749,244: POKE 23750,9: STOP : REM 2040 Printer
3 POKE 23749,34: POKE 23750,254: STOP : REM SPIRIT-80 Printer
4 POKE 65057,0: RANDOMIZE USR 64815: STOP : REM Small-screen COPY
5 POKE 65057,1: RANDOMIZE USR 64815: STOP : REM Large-screen COPY

(EDITORS NOTE: You may use HOT-Z or your favorite hex loader to input the machine code for this project. If you don’t have a hex loader program, we’ve provided one for you in listing 1. Enter the hex numbers listed in the table from left to right, top to bottom.)

Start Address=64815
21 FE FD CD DA FD 21 00 40 06 08
CD 54 FD 21 00 48 06 08 CD 54 FD
21 00 50 06 06 CD 54 FD 21 06 FE
CD DA FD C9 C5 11 C4 FD CD 70 FD
CD 19 FE 28 0C 11 20 00 AF ED 52
11 C8 FD CD 70 FD C1 10 E5 C9 E5
CD CC FD E1 06 20 C5 E5 D5 11 C4
FD 06 08 7E 12 24 13 10 FA D1 62
6B 06 08 C5 E5 06 08 CD 19 FE 28
02 06 04 CB 06 CB 11 CD 19 FE 28
06 CB 0E CB 06 CB 11 23 10 EE 79
CD 81 FE CD 19 FE 79 C4 81 FE E1
C1 10 D4 E1 23 C1 10 BC E5 21 F6
FD CD DA FD E1 C9 00 00 00 00 00
00 00 00 CD 0E FE 21 E6 FD CD 19
FE 28 03 21 EE FD C5 06 04 7E CD
81 FE 23 10 F9 C1 C9 1B 4B 00 01
00 00 00 00 1B 4B 00 02 00 00 00
00 0D 0A 00 00 00 00 00 00 1B 31
00 00 00 00 00 00 1B 32 00 00 00
Checksum=23491
Start Address=65035
00 00 00 0E 05 0D C8 3E 20 CD 81
FE 18 F7 E5 21 21 FE CB 46 E1 C9
00 18 00 FE 5E 20 3F 3E 0A 32 23
FE C9 FE 5E 20 07 F5 AF 32 23 FE
18 49 FE 40 30 0F D6 30 07 07 07
07 32 66 FE 3E 2C 32 23 FE C9 D6
37 18 EF FE 40 30 0E D6 30 4F 3A
66 FE 81 F5 AF 32 23 FE 18 20 D6
37 18 F0 00 FE 60 20 0E 3E 81 CD
81 FE 3E 1B CD 81 FE 3E 49 18 08
CD 81 FE FE 0D C0 3E 0A F5 CD 09
20 38 02 CF 0C DB BF CB 47 28 0A
DB 7F CB 67 20 ED F1 D3 7F C9 AF
D3 FB 3D D3 7B D3 FB F1 F5 D3 7B
3E F7 D3 FB 3E FF D3 FB F1 C9
Checksum=20269

Listing 1: TS2068 Hex Loader

  10 REM TS2068 Hex Loader
20 REM Enter A,B,C,D,E,& F as Upper Case Letters
100 CLS
110 PRINT "Start Address? ": INPUT sa
115 LET a=sa
120 CLS : PRINT "Start Address=";sa
130 LET sum=0
140 FOR l=1 TO 20
150 FOR c=1 TO 30 STEP 3
160 INPUT h$
170 IF h$="" THEN LET h$="00"
180 IF h$="s" THEN GO TO 310
190 IF LEN h$<>2 THEN GO TO 160
200 LET x$=h$(1): LET y$=h$(2)
210 IF CODE x$<=57 THEN LET x=CODE x$-48: GO TO 230
220 LET x=CODE x$-55
230 IF CODE y$<=57 THEN LET y=CODE y$-48: GO TO 250
240 LET y=CODE y$-55
250 LET z=(16*x)+y
255 IF z<0 OR z>255 THEN PRINT AT l,c;"??": BEEP .5,10: GO TO 160
260 PRINT AT l,c;h$
270 POKE a,z
280 LET sum=sum+z: LET a=a+1
290 NEXT c
300 NEXT l
310 PRINT AT 21,0;"Checksum=";sum;" OK? Y/N"
320 PAUSE 4↑4
330 IF INKEY$="y" OR INKEY$="Y" THEN GO TO 360
340 IF INKEY$="n" OR INKEY$="N" THEN GO TO 115
350 GO TO 320
360 CLS : PRINT "Save? Y/N"
370 PAUSE 4↑4
380 IF INKEY$="y" OR INKEY$="Y" THEN SAVE "printdrvr"CODE 64815,384
390 IF INKEY$<>"n" OR INKEY$<>"N" THEN GO TO 360
400 GO TO 100

POKE’s (address and decimal value to be POKEd):

Decimal  Hex    Label  POKE

64841    FD48   -----  6 gives a copy of the upper 22 lines of the
                       screen.
                       8 copies all 24 lines of the screen.

64920    FD98   -----  17 for printers where the MSB activates the
                       top pin.
                       25 where MSB drives bottom pin.

64931    FDA3   -----  (same as 64920).

64988    FDDC   -----  Length of the longest code which will be sent
                       to the printer to put it in the graphics mode,
                       etc. Max. equals 8.

64998    FDE6   grf1   This and next seven bytes (if required) should
                       be POKEd with the code sequence required by the
                       printer to give 640 graphics dots on a line.
                       Any bytes not used should contain zero (NOP).

65006    FDEE   grf2   Code sequence for 1280 dots.

65014    FDF6   crlf   Code sequence for Carriage Return/Line Feed as
                       required by printer.

65022    FDFE   graf   Code sequence to put printer in graphics mode.

65030    FE06   norm   Code sequence to put printer in normal (non-
                       graphics) mode.

65039    FE0F   marg   Left margin for screen copy.
                + 1

65057    FE21   flgz   0 for small-sized screen copy.
                       1 for large.

65132    FE6C   -----  Printer-specific codes which print the English
65137    FE71          pound sign. In example shown, 128d (81h) prints
65142    FE76          this symbol on the dot-matrix printer, and the
                       sequence of 27d (1Bh) (ESC) followed by 73d (49h)
                       prints it on the daisy-wheel printer.
                       (Fortunately, these codes do not interfere on
                       printer for which they are not intended.) POKE
                       to zero (NOP) if not used.

65152    FE80   -----  0 if no line feed desired at end of each line.
                       10 for line feed.

65155    FE83   rdy?   9 for 2068.
                + 1    84 for Spectrum.

65156    FE84   rdy?   32 for 2068.
                + 2    31 for Spectrum.

Labels:

To assist with an understanding of the machine code, a brief meaning of the labels is given below:

copy  Start of screen copier, which ends at "flgz". Also, graphics
      set-up code to printer.
sec1  Copies upper third of screen.
sec2  Copies center third of screen.
sec3  Copies lower third of screen.
nmrl  Normal (non-graphics) set-up to printer.
ecpy  End of basic copy routine. Subroutines for sections follow.
sect  Start of section copier.
sml_  Jumps here for small screen copy.
esec  End of section copier. Subroutines for rows follow.
row_  Start of row copier.
row2  Jump address for DJNZ.
char  Start of "character" copier.
ftch  Fetch next "character."
fch2  Jump address for DJNZ.
out_  Send "character" out to printer, one vertical strip of dots at
      a time.
out2  Jump address for DJNZ.
ldC_  Load C register with vertical strip to be sent.
ldC2  Jump address for DJNZ.
sml2  Jumps here if small screen copy.
outC  Sends contents of C register to printer via A register.
eout  End of "out_" routine.
echr  End of "char" routine.
erow  End of "row_" routine.
stoC  Temporary store for "character" to be loaded into C register.
sto2  Second half of "stoC". Contents vary depending on size of
      screen copy.
esto  End of "stoC".
srow  Routine used at start of each row.
code  Routine used to send set-up codes, etc.
cod2  Jump address for DJNZ.
ecod  End of "code".
grf1  8 bytes for code sequence which tells printer that 640 dots
      follow. Used with small screen copy.
grf2  8 bytes for code sequence which tells printer that 1280 dots
      follow. Used with large screen copy.
crlf  8 bytes for Carriage-Return/Line-Feed code sequence.
graf  8 bytes for code sequence to put printer in graphics mode.
norm  8 bytes for code sequence to put printer in normal
      (non-graphics) mode.
marg  Routine for left margin.
mrg2  Jump for DJNZ.
emrg  End of "marg".
size  Routine to determine size of screen copy.
esiz  End of "size".
flgz  Flag which determines size of screen copy.
↑pnt  Start of "up-arrow" print routine.
jmp0  Jomps here after "up-arrow" activity.
jmp1  Jumps here if up arrow sent.
jmp2  Jumps here if next-to-last character was up arrow.
not↑  Jumps here if present character not up arrow. Handles first hex
      character.
mult  Multiplies first hex character by 16 and stores in "accu".
sub1  Subroutine if first hex character exceeds 9.
jmp3  Jumps here to handle second hex character.
add_  Adds second hex character to sixteen times first hex character.
sub2  Subroutine if second hex character exceeds 9.
accu  Store for 16 times first hex character.
lpnt  The LPRINT routine.
pnto  Prints text, providing a line feed (if selected) and carriage
      return at end of each line.
prnt  Sends byte in register A to printer.
rdy?  Calls BREAK routine in ROM preparatory to testing printer's BUSY
      line.
tast  Test of Tasman interface "printer busy."
aert  Test of Aerco interface "printer busy."
aerp  Aerco interface output routine.
tasp  Tasman interface output routine.

Machine Code-

ADDR HEXCODE LABEL MNEMONIC
FD2F 21FEFD copy LD HL,graf
FD32 CDDAFD CALL code
FD35 210040 sec1 LD HL,4000
FD38 0608 LD B,08
FD3A CD54FD CALL sect
FD3D 210048 sec2 LD HL,4800
FD40 0608 LD B,08
FD42 CD54FD CALL sect
FD45 210050 sec3 LD HL,5000
FD48 0606 LD B,06
FD4A CD54FD CALL sect
FD4D 2106FE nrml LD HL,norm
FD50 CDDAFD CALL code
FD53 C9 ecpy RET
FD54 C5 sect PUSH BC
FD55 11C4FD LD DE,stoC
FD58 CD70FD CALL row_
FD5B CD19FE CALL size
FD5E 280C JR Z,sml_
FD60 112000 LD DE,0020
FD63 AF XOR A
FD64 ED52 SBC HL,DE
FD66 11C8FD LD DE,sto2
FD69 CD70FD CALL row_
FD6C C1 sml_ POP BC
FD6D 10E5 DJNZ,sect
FD6F C9 esec RET
FD70 E5 row_ PUSH HL
FD71 CDCCFD CALL srow
FD74 E1 POP HL
FD75 0620 LD B,20
FD77 C5 row2 PUSH BC
FD78 E5 char PUSH HL
FD79 D5 PUSH DE
FD7A 11C4FD ftch LD DE,stoC
FD7D 0608 LD B,08
FD7F 7E fch2 LD A,(HL)
FD80 12 LD (DE),A
FD81 24 INC H
FD82 13 INC DE
FD83 10FA DJNZ,fch2
FD85 D1 out_ POP DE
FD86 62 LD H,D
FD87 6B LD L,E
FD88 0608 LD B,08
FD8A C5 out2 PUSH BC
FD8B E5 PUSH HL
FD8C 0608 ldC_ LD B,08
FD8E CD19FE CALL size
FD91 2802 JR Z,ldC2
FD93 0604 LD B,04
FD95 CB06 ldC2 RLC (HL)
FD97 CB11 RL C
FD99 CD19FE CALL size
FD9C 2806 JR Z,sml2
FD9E CB0E RRC (HL)
FDA0 CB06 RLC (HL)
FDA2 CB11 RL C
FDA4 23 sml2 INC HL
FDA5 10EE DJNZ,ldC2
FDA7 79 outC LD A,C
FDA8 CD81FE CALL prnt
FDAB CD19FE CALL size
FDAE 79 LD A,C
FDAF C481FE CALL NZ,prnt
FDB2 E1 POP HL
FDB3 C1 POP BC
FDB4 10D4 eout DJNZ,out2
FDB6 E1 POP HL
FDB7 23 INC HL
FDB8 C1 POP BC
FDB9 10BC echr DJNZ,row2
FDBB E5 PUSH HL
FDBC 21F6FD LD HL,crlf
FDBF CDDAFD CALL code
FDC2 E1 POP HL
FDC3 C9 erow RET
FDC4 00 stoC NOP
FDC5 00 NOP
FDC6 00 NOP
FDC7 00 NOP
FDC8 00 sto2 NOP
FDC9 00 NOP
FDCA 00 NOP
FDCB 00 esto NOP
FDCC CD0EFE srow CALL marg
FDCF 21E6FD LD HL,grf1
FDD2 CD19FE CALL size
FDD5 2803 JR Z,code
FDD7 21EEFD LD HL,grf2
FDDA C5 code PUSH BC
FDDB 0604 LD B,04
FDDD 7E cod2 LD A,(HL)
FDDE CD81FE CALL prnt
FDE1 23 INC HL
FDE2 10F9 DJNZ,cod2
FDE4 C1 POP BC
FDE5 C9 ecod RET
FDE6 1B grf1 DEC DE
FDE7 4B LD C,E
FDE8 00 NOP
FDE9 010000 LD BC,0000
FDEC 00 NOP
FDED 00 NOP
FDEE 1B grf2 DEC DE
FDEF 4B LD C,E
FDF0 00 NOP
FDF1 02 LD (BC),A
FDF2 00 NOP
FDF3 00 NOP
FDF4 00 NOP
FDF5 00 NOP
FDF6 0D crlf DEC C
FDF7 0A LD A,(BC)
FDF8 00 NOP
FDF9 00 NOP
FDFA 00 NOP
FDFB 00 NOP
FDFC 00 NOP
FDFD 00 NOP
FDFE 1B graf DEC DE
FDFF 310000 LD SP,0000
FE02 00 NOP
FE03 00 NOP
FE04 00 NOP
FE05 00 NOP
FE06 1B norm DEC DE
FE07 320000 LD (0000),A
FE0A 00 NOP
FE0B 00 NOP
FE0C 00 NOP
FE0D 00 NOP
FE0E 0E05 marg LD C,05
FE10 0D mrg2 DEC C
FE11 C8 RET Z
FE12 3E20 LD A,20
FE14 CD81FE CALL prnt
FE17 18F7 emrg JR mrg2
FE19 E5 size PUSH HL
FE1A 2121FE LD HL,flgz
FE1D CB46 BIT 0,(HL)
FE1F E1 POP HL
FE20 C9 esiz RET
FE21 00 flgz NOP
FE22 1800 ↑pnt JR jmp0
FE24 FE5E jmp0 CP 5E
FE26 203F JR NZ,lpnt
FE28 3E0A jmp1 LD A,0A
FE2A 3223FE LD (FE23),A
FE2D C9 RET
FE2E FE5E jmp2 CP 5E
FE30 2007 JR NZ,not↑
FE32 F5 PUSH AF
FE33 AF XOR A
FE34 3223FE LD (FE23),A
FE37 1849 JR rdy?
FE39 FE40 not↑ CP 40
FE3B 300F JR NC,sub1
FE3D D630 SUB 30
FE3F 07 mult RLCA
FE40 07 RLCA
FE41 07 RLCA
FE42 07 RLCA
FE43 3266FE LD (accu),A
FE46 3E2C LD A,2C
FE48 3223FE LD (FE23),A
FE4B C9 RET
FE4C D637 sub1 SUB 37
FE4E 18EF JR mult
FE50 FE40 jmp3 CP 40
FE52 300E JR NC,sub2
FE54 D630 SUB 30
FE56 4F add_ LD C,A
FE57 3A66FE LD A,(accu)
FE5A 81 ADD A,C
FE5B F5 PUSH AF
FE5C AF XOR A
FE5D 3223FE LD (FE23),A
FE60 1820 JR rdy?
FE62 D637 sub2 SUB 37
FE64 18F0 JR add_
FE66 00 accu NOP
FE67 FE60 lpnt CP 60
FE69 200E JR NZ,pnto
FE6B 3E81 LD A,81
FE6D CD81FE CALL prnt
FE70 3E1B LD A,1B
FE72 CD81FE CALL prnt
FE75 3E49 LD A,49
FE77 1808 JR prnt
FE79 CD81FE pnto CALL prnt
FE7C FE0D CP 0D
FE7E C0 RET NZ
FE7F 3E0A LD A,0A
FE81 F5 prnt PUSH AF
FE82 CD0920 rdy? CALL brek
FE85 3802 JR C,tast
FE87 CF RST 08H
FE88 0C ERROR D
FE89 DBBF tast IN A,(BF)
FE8B CB47 BIT 0,A
FE8D 280A JR Z,tasp
FE8F DB7F aert IN A,(7F)
FE91 CB67 BIT 4,A
FE93 20ED JR NZ,rdy?
FE95 F1 aerp POP AF
FE96 D37F OUT (7F),A
FE98 C9 RET
FE99 AF tasp XOR A
FE9A D3FB OUT (FB),A
FE9C 3D DEC A
FE9D D37B OUT (7B),A
FE9F D3FB OUT (FB),A
FEA1 F1 POP AF
FEA2 F5 PUSH AF
FEA3 D37B OUT (7B),A
FEA5 3EF7 LD A,F7
FEA7 D3FB OUT (FB),A
FEA9 3EFF LD A,FF
FEAB D3FB OUT (FB),A
FEAD F1 POP AF
FEAE C9 RET

It is hoped that some of the ideas in this code will assist not only Mr. Cary, but other members of the 2068 family as well.

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