In 1981, Sinclair Research introduced the ZX Printer. This was a small printer that connected to their ZX81 computer. It used special paper with an aluminium coating that could be burnt off by a passing print head. Sinclair’s later ZX Spectrum computer was also compatible with the ZX Printer.
A compatible printer called the Alphacom 32 / Timex Sinclair 2040 was also released. This used standard thermal paper. It used an external power supply instead of relying on that of the ZX81 or ZX Spectrum.
Both the ZX81 and ZX Spectrum are Z80-based, and so is the RC2014 computer. So I wondered if the RC2014 could use a ZX Printer? The belt inside my ZX Printer has perished and no longer works. I do have a working Alphacom 32 printer. Researching how I could interface the two devices, I found that Spencer Owen had already attempted this. He was able to get some output on the printer, but nothing usable.
The ZX Printer uses the following lines from the Z80 microprocessor.
- A2 – LOW when addressing the printer.
- IORQ – LOW when addressing the printer.
- RD – LOW when reading
- WR – LOW when writing
- D0 – HIGH when reading if the printer is ready for the next data bit
- D1 – Write HIGH to slow the motor. Write LOW for a faster motor speed.
- D2 – Write HIGH to stop the motor, write LOW to start the motor.
- D6 – LOW when reading if the printer is present.
- D7 – HIGH when reading if it’s the start of a new line. Write HIGH to print a bit.
- A7 – HIGH on the Alphacom 32 / Timex Sinclair 2040 when addressing the printer. The ZX Printer ignores this.
The printer also uses GND and +5V. The ZX Printer also uses +9V on the ZX81 and ZX Spectrum edge connector. The Alphacom 32 / Timex Sinclair 2040 doesn’t use +9V.
As decoding on just A2 would mean the printer showing on many addresses, I decided to use a 74HCT688 to decode A0 to A7 instead. This means I can avoid IO address clashes with other RC2014 modules. I decided to make this configurable via DIP switches to make it easy to move IO addresses. I send the output from the 74HCT688 to A2 on the printer. I wired A7 to +5V as I no longer need to decode this. I pass the other lines from the RC2014 to a ZX Spectrum compatible edge connector.
As the RC2014 doesn’t have a +9V power supply, I added a barrel socket for an external supply. I wired this to be center negative so I could use a ZX Spectrum power supply. As I don’t have a working ZX Printer, I’ve not been able to test this part of the circuit yet. The markings on the PCB are from the footprint, and these are the wrong way round.

Example Z80 Assembly Language
I set the DIP switches on my board to port $1. I also have an RC2014 Digital IO module on port $0. In my assembly language program, I use this to show the current line being printed, but this is optional.
The ZX Printer’s resolution is 256 pixels wide, so for this example, I converted the RC2014 logo to 256 pixels wide. This gave me a height of 42 lines for the image. The image I converted from didn’t scale very well, so it’s a bit of messy print.
I based my code on the printer routines in the ZX Spectrum ROM. The COPY command on a Spectrum prints out the current contents of the screen. I used this as my starting point, and modified the code to see a bitmap instead.
As timing is important, I have disabled interrupts while the code runs.
OUTPUT zxprinter.z80
; Assemble using SjASMPlus.
;
; This program will print a bitmap image to a ZX printer.
; This code is based off code in the ZX Spectrum ROM.
; https://skoolkid.github.io/rom/asm/0ECD.html
;
; Robert Price - www.robertprice.co.uk
; DEFINE+ UseDIO ; Uncomment this line to use the Digital
; IO board to show the current line being
; printed.
PORT EQU $1 ; The output port to use for the printer.
IFDEF UseDIO
DIOPORT EQU $0 ; the output port for a RC2014 digial IO
; board. This is used to show the current
; line being printed.
ENDIF
WIDTH EQU 256 ; the width of the image in pixels.
HEIGHT EQU 42 ; how many lines in the image to print.
ORG $9000 ; The start of the program. This is where
; the program will be loaded into memory.
di ; disable interrupts
ld b, HEIGHT ; the number of lines to print is in B.
ld hl, Buffer ; The address of the bitmap stored in HL
Copy_Buffer:
push bc
call Copy_Line ; print the current line
pop bc
IFDEF UseDIO
ld a, b ; show the current line being printed on
; the Digital IO LEDs.
out (DIOPORT), a
ENDIF
djnz Copy_Buffer ; loop back to print the next line.
IFDEF UseDIO
ld a, 0 ; turn off the Digital IO LEDs
out (DIOPORT), a
ENDIF
Copy_End:
ld a, $04 ; Bit 2 high stops the printer
out (PORT), a ; stop the printer
ei ; enable interrupts
ret ; end the program
Copy_Line:
ld a, b ; Copy the pixel-line number.
cp $03 ; The A register will hold 0 until the
; last two lines are being handled.
sbc a, a
and $02
out (PORT), a ; slow the motor for the last two lines.
ld d, a ; the D register will hold either 0 or 2.
Copy_L_1;
; on a ZX Spectrum this would test for
; breaks and stop the printer.
; let's add our own delay here to allow
; the printer to catch up.
push bc
ld b, $ff
.delay:
nop
djnz .delay
pop bc
Copy_L_2:
in a, (PORT) ; fetch the status of the printer.
add a, a ; double the value of A. This moves bit 6
; which is the printer present flag to bit
; 7 and the sign flag.
ret m ; make an immediate return if the printer
; is not present. (sign negative flag)
jr nc, Copy_L_1 ; wait for the stylus to be ready.
ld c, $20 ; there are 32 bytes.
Copy_L_3:
ld e, (hl) ; fetch a byte from the buffer.
inc hl ; update the pointer
ld b, $08 ; eight bits per byte
Copy_L_4:
rl d ; move D left
rl e ; move each bit into the carry
rr d ; move D back again, picking up the carry
; from E. The carry bit was the bit to print.
Copy_L_5:
in a, (PORT) ; fetch the status of the printer
rra ; move bit 0 into the carry flag.
; If bit 0 is high,
; the printer is ready to receive data.
jr nc, Copy_L_5 ; loop until the printer is ready
ld a, d ; load the byte to send to the printer.
; Bit 2 low starts the motor,
; bit 1 high slows the motor,
; bit 7 high prints
out (PORT), a ; send to the printer
djnz Copy_L_4 ; print each bit.
dec c ; decreate the line byte counter
jr nz, Copy_L_3 ; loop until all 32 bytes are printed.
ret
; The image we want to print
; In this case, it's the RC2014 logo at 256 pixels wide and 42 pixles high.
Buffer:
dc $00, $00, $00, $00, $82, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
dc $00, $00, $00, $00, $82, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
dc $00, $00, $00, $00, $82, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
dc $00, $04, $10, $43, $08, $20, $00, $02, $08, $20, $82, $00, $00, $01, $04, $10
dc $40, $00, $04, $10, $c2, $08, $00, $00, $02, $08, $00, $00, $06, $18, $01, $04
dc $00, $04, $10, $c2, $08, $30, $00, $02, $08, $20, $06, $00, $00, $41, $04, $10
dc $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $10
dc $60, $00, $04, $30, $82, $0c, $00, $00, $02, $0c, $00, $00, $04, $18, $01, $06
dc $00, $04, $30, $82, $08, $30, $00, $02, $08, $01, $06, $00, $00, $41, $04, $10
dc $c0, $00, $08, $20, $82, $0c, $00, $00, $06, $1c, $00, $00, $04, $18, $00, $06
dc $00, $0c, $30, $c6, $18, $70, $00, $06, $18, $61, $86, $00, $00, $c3, $0c, $30
dc $c0, $00, $0c, $31, $86, $1c, $00, $00, $06, $18, $00, $00, $0c, $38, $03, $0c
dc $00, $ff, $ff, $ff, $ff, $f0, $00, $7f, $ff, $ff, $fe, $00, $0f, $ff, $ff, $ff
dc $c0, $00, $ff, $ff, $ff, $fc, $00, $00, $7f, $f8, $00, $00, $7f, $f8, $3f, $fc
dc $00, $08, $37, $df, $70, $40, $00, $06, $fb, $ef, $0c, $20, $00, $df, $7d, $e0
dc $84, $00, $0d, $f7, $84, $10, $00, $00, $04, $18, $00, $00, $08, $30, $02, $0c
dc $00, $08, $20, $00, $00, $41, $01, $04, $00, $00, $08, $30, $20, $c0, $00, $01
dc $86, $02, $18, $00, $04, $10, $40, $01, $04, $10, $00, $00, $08, $30, $02, $08
dc $00, $18, $70, $00, $00, $41, $81, $06, $00, $00, $08, $30, $20, $c0, $00, $01
dc $07, $06, $18, $00, $04, $10, $60, $01, $08, $30, $00, $00, $08, $30, $00, $18
dc $00, $10, $60, $00, $00, $43, $01, $06, $00, $00, $08, $30, $20, $c0, $00, $01
dc $06, $04, $18, $00, $04, $00, $c0, $02, $08, $30, $00, $00, $08, $30, $04, $18
dc $00, $38, $e0, $00, $00, $c3, $03, $1c, $00, $00, $1c, $70, $71, $c0, $00, $23
dc $8e, $06, $38, $00, $0c, $71, $c0, $07, $1c, $70, $00, $00, $1c, $70, $0e, $38
dc $01, $ff, $e0, $00, $0f, $ff, $3f, $fc, $00, $00, $ff, $e3, $ff, $80, $00, $1f
dc $fe, $7f, $f8, $00, $7f, $ff, $c0, $3f, $ff, $f0, $00, $01, $ff, $e0, $7f, $f8
dc $00, $10, $40, $00, $00, $82, $02, $0c, $00, $00, $00, $00, $00, $00, $00, $c3
dc $00, $0c, $30, $02, $08, $20, $80, $02, $00, $60, $00, $00, $18, $00, $04, $10
dc $00, $00, $c0, $00, $00, $82, $02, $08, $00, $00, $00, $00, $00, $00, $00, $c3
dc $00, $0c, $30, $03, $00, $00, $80, $00, $10, $60, $00, $04, $18, $00, $08, $30
dc $00, $20, $c0, $00, $00, $06, $00, $18, $00, $00, $00, $00, $00, $00, $00, $83
dc $00, $08, $30, $03, $00, $41, $80, $00, $10, $60, $00, $04, $18, $00, $08, $30
dc $00, $20, $c0, $00, $01, $06, $04, $18, $00, $00, $00, $00, $00, $00, $00, $83
dc $00, $08, $30, $03, $00, $41, $80, $00, $10, $60, $00, $04, $18, $00, $08, $30
dc $03, $ff, $c0, $00, $0f, $fe, $3f, $f8, $00, $00, $00, $00, $00, $00, $0f, $ff
dc $00, $ff, $f0, $7e, $07, $ff, $80, $01, $ff, $e0, $00, $7f, $f0, $00, $ff, $f0
dc $00, $61, $80, $00, $03, $fe, $0e, $38, $00, $00, $00, $00, $00, $00, $01, $ff
dc $00, $18, $70, $0e, $00, $c3, $80, $00, $30, $c0, $00, $1c, $70, $00, $18, $70
dc $00, $41, $04, $10, $41, $00, $04, $30, $00, $00, $00, $00, $02, $08, $21, $80
dc $00, $10, $60, $04, $00, $03, $00, $00, $20, $c0, $00, $08, $20, $00, $10, $60
dc $00, $41, $04, $10, $43, $00, $00, $30, $00, $00, $00, $00, $06, $18, $41, $80
dc $00, $10, $60, $06, $00, $83, $00, $00, $20, $c0, $00, $08, $30, $00, $10, $60
dc $00, $41, $04, $10, $83, $00, $08, $30, $00, $00, $00, $00, $06, $10, $41, $80
dc $00, $10, $60, $0e, $00, $83, $00, $00, $20, $c0, $00, $00, $60, $00, $10, $60
dc $00, $41, $0c, $30, $83, $00, $08, $30, $00, $00, $00, $00, $04, $10, $41, $80
dc $00, $10, $60, $0c, $00, $83, $00, $00, $21, $c0, $00, $18, $60, $00, $10, $e0
dc $0f, $ff, $ff, $ff, $ff, $00, $ff, $f0, $00, $00, $00, $00, $7f, $ff, $ff, $80
dc $03, $ff, $c0, $fc, $1f, $ff, $00, $07, $ff, $80, $01, $ff, $e0, $03, $ff, $e0
dc $00, $c3, $ff, $ff, $86, $00, $18, $70, $00, $00, $00, $00, $0e, $fb, $ff, $00
dc $00, $20, $c0, $0c, $01, $86, $00, $00, $61, $80, $00, $10, $c0, $00, $30, $80
dc $00, $83, $00, $00, $04, $10, $10, $60, $00, $00, $00, $01, $04, $00, $00, $00
dc $00, $20, $80, $08, $01, $06, $00, $00, $41, $00, $00, $10, $42, $08, $20, $82
dc $00, $83, $00, $00, $04, $18, $10, $60, $00, $00, $00, $03, $0e, $00, $00, $00
dc $00, $20, $c0, $18, $01, $06, $00, $00, $41, $80, $00, $30, $82, $08, $20, $83
dc $00, $83, $00, $00, $04, $18, $10, $60, $00, $00, $00, $02, $0c, $00, $00, $00
dc $00, $00, $c0, $18, $01, $06, $00, $00, $c3, $80, $00, $20, $82, $08, $20, $03
dc $01, $86, $00, $00, $0c, $38, $10, $e0, $00, $00, $00, $02, $0c, $00, $00, $00
dc $00, $41, $80, $18, $03, $0e, $00, $00, $c3, $00, $00, $20, $82, $18, $61, $86
dc $1f, $fe, $00, $00, $ff, $fb, $ff, $e0, $00, $00, $00, $3f, $fc, $00, $00, $00
dc $07, $ff, $81, $f8, $3f, $fc, $00, $0f, $ff, $00, $03, $ff, $ff, $ff, $ff, $fe
dc $01, $06, $00, $00, $08, $30, $30, $c0, $00, $00, $00, $06, $1c, $00, $00, $00
dc $00, $41, $00, $f0, $02, $0c, $00, $00, $87, $00, $01, $f7, $df, $70, $41, $be
dc $01, $04, $00, $00, $08, $30, $20, $c0, $00, $00, $06, $00, $18, $00, $00, $10
dc $c0, $40, $0c, $00, $02, $0c, $00, $00, $82, $00, $00, $00, $00, $00, $41, $00
dc $01, $0e, $00, $00, $08, $30, $20, $c0, $00, $01, $06, $04, $18, $00, $00, $30
dc $c0, $02, $0c, $00, $02, $0c, $00, $01, $87, $00, $00, $00, $00, $00, $41, $80
dc $03, $0c, $00, $00, $08, $30, $20, $c0, $00, $01, $06, $04, $18, $00, $00, $20
dc $c0, $82, $0c, $00, $06, $1c, $00, $01, $06, $00, $00, $00, $00, $00, $03, $00
dc $03, $0c, $00, $00, $18, $60, $61, $c0, $00, $03, $0e, $0c, $38, $00, $00, $30
dc $c0, $c3, $0c, $00, $06, $18, $00, $01, $8e, $00, $00, $00, $00, $00, $c3, $00
dc $3f, $fc, $00, $01, $ff, $e3, $ff, $80, $00, $1f, $fc, $7f, $f8, $00, $03, $ff
dc $cf, $ff, $f8, $00, $7f, $f8, $00, $1f, $fe, $00, $00, $00, $00, $0f, $ff, $00
dc $02, $18, $00, $00, $10, $60, $41, $00, $00, $03, $00, $08, $20, $80, $00, $61
dc $80, $06, $18, $40, $06, $00, $00, $03, $08, $00, $00, $00, $00, $00, $82, $00
dc $02, $18, $00, $00, $10, $40, $01, $00, $00, $83, $00, $08, $20, $82, $18, $61
dc $80, $04, $10, $41, $06, $00, $10, $c2, $08, $20, $c0, $00, $00, $00, $02, $00
dc $04, $18, $00, $00, $00, $60, $00, $08, $20, $83, $00, $08, $20, $86, $10, $41
dc $80, $04, $10, $41, $06, $00, $30, $82, $08, $20, $c0, $00, $00, $01, $06, $00
dc $04, $18, $00, $00, $00, $c0, $02, $08, $20, $83, $00, $08, $01, $04, $10, $41
dc $80, $04, $10, $c2, $0e, $00, $20, $82, $08, $20, $c0, $00, $00, $01, $06, $00
dc $ff, $f8, $00, $03, $ff, $c0, $3f, $ff, $ff, $ff, $01, $ff, $ff, $ff, $ff, $ff
dc $80, $ff, $ff, $ff, $fc, $03, $ff, $ff, $ff, $ff, $80, $00, $00, $1f, $fe, $00
dc $7f, $f8, $00, $01, $ff, $c0, $3f, $ff, $ff, $fe, $00, $ff, $ff, $ff, $ff, $ff
dc $80, $7f, $ff, $ff, $fc, $01, $ff, $ff, $ff, $ff, $80, $00, $00, $1f, $fe, $00
dc $3e, $f8, $00, $01, $f7, $c0, $1f, $7d, $ff, $be, $00, $7b, $ef, $fe, $fb, $ef
dc $80, $3e, $fb, $df, $7c, $01, $f7, $df, $79, $ef, $80, $00, $00, $0f, $bc, $00