This article describes how to connect a Commodore 64 compatible printer to an
IBM PC compatible computer.  The information originally appeared in an article
that I wrote for the Tech Forum section of the March 1995 issue of Nuts & Volts
magazine.  This information may be used and distributed so long as proper
credit is given to the author and Nuts & Volts magazine.  Copyright (C) 1995 by
John Keyerleber and Nuts & Volts Magazine.

The problem with Commodore 64 compatible printers is that these devices use the
Commodore synchronous serial interface to communicate with the C64.  An IBM PC
compatible printer port is a parallel interface, however it is possible to use
this parallel port to emulate the C64 serial interface by constructing a
special cable and writing a little bit of software.

The cable is used to connect the PC DB25 pin parallel printer port to the 6 pin
DIN serial port on the C64 compatible printer.  The parts needed are one DB25
male connector (Radio Shack #276-1429), one 6 pin DIN plug (RS #274-020), and
some six conductor cable (RS #278-874 or equivalent).  Note that the cable
length should be kept to less than six feet.  The wiring connections and signal
descriptions for this cable are given as follows:

Commodore 64 DIN plug pin:    Parallel printer DB25 connector pin:
	1 (SRQ IN)                    2 (DATA0)
	2 (GND)                       20 (GND)
	3 (SER ATN)                   3 (DATA1)
	4 (SER CLK)                   4 (DATA2)
	5 (SER DAT)                   5 (DATA3)
	6 (RST)                       6 (DATA4)

The software uses the PC parallel port to emulate a C64 serial port.  The
example program, C64.C (Listing 1), is written in Borland's Turbo C.  It reads
input and sends each character to the printer.  It can be used as a filter in
an MS-DOS command line pipe.  For example, DOS commands such as:  dir | c64
would print a directory listing, or type a_file | c64 would print the contents
of a file.

I have also written an MS-DOS device driver which can be used to allow any PC
application to print to a C64 compatible printer, and it supports multiple
printers connected to a single PC parallel port.  The listing for this software
is too lengthy to print, however I will make this software and assembled cables
available to Commodore 64 enthusiasts for a nominal charge; just write me for
details.  With these C64 compatible printers often selling for less than $25 at
garage sales and flea markets, it's easy to add a couple of additional
"scratch" printers to any PC system.

John Keyerleber
26300 Chardonview Drive
Cleveland, OH  44143
(216) 261-9676
E-mail:  jkeyerleber@bailey.com

Listing 1:

#include <stdio.h>
#include <ctype.h>
#include <dos.h>

#define  PORTADR  0x378    // LPT1=0x378, LPT2 = 0x278
#define  PRINTADR 0x04     // C64 compatible printer address
#define  SRQ      0x01     // C64 SRQ IN signal
#define  ATN      0x02     // C64 ATN signal
#define  CLK      0x04     // C64 CLK signal
#define  DAT      0x08     // C64 DAT signal
#define  RST      0x10     // C64 RST signal

// function prototypes
void initc64(void);
void putc64(unsigned char);
void puts64(char *);
void putbyte(unsigned char, unsigned char);

// function main() loops to read input characters and send them to the printer
void main(void)
{
	char buff[128], *ptr;

	initc64();
	while(fgets(buff, 80, stdin))
	{
		for(ptr = buff; *ptr; putc64(*ptr++));
	}
}

// function init64() initializes the driver and the C64 compatible printer
void initc64(void)
{
	// set initial port output value to all bits high
	outportb(PORTADR, RST | SRQ | ATN | CLK | DAT);

	// initialize printer: RST=0, then RST=1
	outportb(PORTADR, SRQ | ATN | CLK | DAT);
	delay(250);
	outportb(PORTADR, RST | SRQ | ATN | CLK | DAT);
	delay(2250);

	// Set printer to listener: ATN and CLK low, printer will ACK with DAT low
	outportb(PORTADR, RST | SRQ | DAT);
	while((inportb(PORTADR) & DAT));

	// Send printer address (currently set for address 4)
	putbyte(0x20 | PRINTADR, 0);

	// Send printer mode
	putbyte(0x67, 0);
}

// function putc64() sends a byte of data (byteval) to the C64 compatible printer
void putc64(unsigned char byteval)
{
	// Check for upper/lower case conversion
	if (isalpha(byteval))
	{
		byteval = (isupper(byteval)) ? tolower(byteval) : toupper(byteval);
	}
	// Send character
	putbyte(byteval, ATN);
}

// function putbyte clocks the actual byte to the C64 compatible printer bit by bit
void putbyte(unsigned char byteval, unsigned char mode)
{
	register int bitloop;

	// Set CLK high, printer will ACK with DAT high
	outportb(PORTADR, RST | SRQ | CLK | DAT | mode);
	while(!(inportb(PORTADR) & DAT));

	// Loop to output bits of data
	delay(1);
	for (bitloop=0; bitloop<8; bitloop++)
	{
		outportb(PORTADR, RST | SRQ | ((byteval & 1) ? DAT : 0) | mode);
		delay(1);
		outportb(PORTADR, RST | SRQ | CLK | ((byteval & 1) ? DAT : 0) | mode);
		delay(1);
		byteval >>= 1;
	}

	// Set CLK low and DAT high for end of byte, printer will ACK with DAT low
	outportb(PORTADR, RST | SRQ | DAT | mode);
	while((inportb(PORTADR) & DAT));
}

