Provides a quick and easy way of getting programs into the
system. Simpler and faster than a serial port, and no RS232
buffers to fit.
This has been implemented and is much more convenient than
re-typing or time-consuming compilation of assembly code into the
FPGA itself.
It requires PD0-7, !STB, and BUSY. The rising edge of the !STB signal loads a register and automatically asserts BUSY. The target system reads this register and automatically asserts BUSY.
Pinout arranged to be compatible with the BurchEd printer port interface. I considered having the data lines sent through a '573 type latch to the CPU data bus. This would save seven FPGA pins but consume scarce PCB space and be less flexible. It could not be programmed to be a printer output port. Hence FPGA pins were used to retain flexibility.
Printer | PWR | 1 | 2 | 182 | 185 | ||||||
D25 | Cable | ||||||||||
1 | 1 | --> | 100R | lpt_n_stb | 181 | 160 | 3 | 4 | 161 | 187 | lpt_n_auto_lf |
14 | 2 | --> | 100R | ----------------------- | -' | ||||||
2 | 3 | --> | 100R | lpt_d<0> | 188 | 162 | 5 | 6 | 163 | 189 | lpt_error |
15 | 4 | <-- | 100R | ----------------------- | -' | ||||||
3 | 5 | --> | 100R | lpt_d<1> | 191 | 164 | 7 | 8 | 165 | 192 | lpt_n_init |
16 | 6 | --> | 100R | ----------------------- | -' | ||||||
4 | 7 | --> | 100R | lpt_d<2> | 193 | 166 | 9 | 10 | 167 | 194 | lpt_n_select |
17 | 8 | --> | 100R | ----------------------- | -' | ||||||
5 | 9 | --> | 100R | lpt_d<3> | 195 | 168 | 11 | 12 | 169 | 199 | lpt_d<4> |
6 | 11 | --> | 100R | ----------------------- | -' | ||||||
7 | 13 | --> | 100R | lpt_d<5> | 200 | 173 | 13 | 14 | 174 | 201 | lpt_d<6> |
8 | 15 | --> | 100R | ----------------------- | -' | ||||||
9 | 17 | --> | 100R | lpt_d<7> | 202 | 175 | 15 | 16 | 176 | 203 | lpt_ack |
10 | 19 | <-- | 100R | ----------------------- | -' | ||||||
11 | 21 | <-- | 100R | lpt_n_busy | 204 | 178 | 17 | 18 | 179 | 205 | lpt_paper |
12 | 23 | <-- | 100R | ----------------------- | -' | ||||||
13 | 25 | <-- | 100R | lpt_selected | 206 | 180 | 19 | 20 | GND | ||
18 to 25 |
10,12, 14,16, 18,20, 22,24 |
--- | GND |
The 100R resistors damp reflections (and limit current if
conflicts occur!).
Input signals require 4k7 pull up resistors.
Output signals should be open-collector.
During implementation the VHDL compiler pointed out there were not enough I/O blocks, so only !INIT, !STB and BUSY were implemented.
A short and simple BASIC program demonstrated the principles by polling the busy flag, then reading the data register and printing it to the screen. The transfer rate was only limited by speed of interpreter and printing/scrolling screen characters. Assembly code is much faster. Short routines were written to read incoming bytes from the slave port while !INIT is high.
I found a 1,363K text file (about a floppy full) took 21 mins to transfer with each byte written to the screen and the whole screen scrolled every 40 chars. This takes a lot of time, since it has to move the screen in software. I swapped the call for three nop codes, and the file transferred in 22 seconds. 2.35 seconds of that was the nop codes. So each byte took about 16 us to transfer. It is faster than copying a floppy. And much faster than tape (300 baud). Works out around 13.96 Mbaud! I have not got code to hand over lines to the interpreter yet but at that rate the transfer overhead is about one second per 64K. Any significant time delay is in processing the bytes in the target.
The Atom is easily programmed to accept ASCII text 'printed' to it by the PC, by changing the OSRDCH vector to point to the slave port. This has to be done in one go, to avoid a half-written vector. There is no 16-bit write command, but there is a 32-bit write which can be used like so:
!#0208=#A000FE55
to set the new OSRDCH to A000, and retaining the original OSWRCH. The latter could be changed to point to a null function so that the download is not slowed by writing to screen. Immediately after this command, the Atom's real keyboard is ignored. When the PC has finished 'typing' in a program, it has to return keyboard control back to the user. It does this by 'typing' in the command:
!#0208=#FE94FE55
to restore vectors. Immediately after this command, the Atom's real keyboard is enabled.
The Atom also has a vector for an OS Command Line Interpreter (OSCLI). This could be changed to point to a completely new OS interpreter, though not a trivial task. It would be simpler to change the filing system vectors (OSBGET, OSBPUT) from their normal tape cassette I/O to printer slave routines. This would allow the PC to appear as if it were a tape recorder, only very much faster. However, this requires the PC to understand the data structure of saved files. This is moderately simple but more complex than a simple keyboard replacement routine.
This was easy to do, about 100 lines of C source file to send bytes from a hard disk file to the printer port. Direct i/o, so not legal in a stricter OS than Win98, but okay just to get started.
Text files require some 'filtering' because the interpreter expects CR from the keyboard but not LF, which it reports as an error. Windows Notepad puts CRLF at the end of lines, so my simple PC program simply discards LF.
Atom software usually exists in Atom-specific file formats which include information about where to load the program and where to start executing code. NB: The multi-byte elements in the structures above are little endian (same as the PC).
Atom Standard format
atom_file_std = // 19 bytes { UINT16 addr_to_load; // UINT16 addr_to_exec; // BYTE reserved[12]; BYTE fixed[2]; // always 0x0d, 0x00 BYTE payload[size]; }Atom-in-PC
atom_file_aipc = // 16 bytes { UINT16 addr_to_load; // UINT16 addr_to_exec; // UINT32 size; // way bigger than likely! :-) BYTE reserved[11]; BYTE reserved[8]; BYTE payload[size]; }
Atom Emulator by Wouter Ras
atom_file_ras = // 22 bytes { BYTE name[16]; UINT16 addr_to_load; // UINT16 addr_to_exec; // UINT16 size; // BYTE payload[size]; }