Recently, I designed and built a serial-port expansion board for my PCPI AppliCard systems which vastly improves serial-port performance. In the next few pages, I hope to present the results of my work and invite feedback from any other AppliCard users who construct a similar device.
The PCPI AppliCard is a co-processor accessory card for the Apple ][ series of personal computers. It includes a Z80 CPU running at either 4 or 6 MHz, 64K of DRAM, bootstrap EPROM, an optional Z80 CTC, and all the necessary logic and buffers to interface the card to the Apple ][ expansion bus. CP/M 2.2, the Z80 CBIOS and user applications run in the RAM on the AppliCard itself.
The Apple ][ functions as an I/O server, providing the AppliCard access to the Apple's screen, disk drives and any other peripheral cards in the Apple for which a device driver exists. The Apple ][ and the AppliCard communicate through a set of I/O ports and a command processor which runs continuously on the Apple ][. Unlike other systems, the AppliCard and Apple ][ do not share memory and there is no way to directly access the memory of one machine from the other.
This distributed system formed by the AppliCard and the Apple ][ allows both processors to run at full speed. As long as there is no I/O to be done, the AppliCard and Apple ][ are completely independent of each other. Although satisfactory for handling all in-system data transfers, this I/O bottleneck, the polled operation of the 6502 command processor, and the time required to scroll the Apple ][ screen severely limit serial port performance.
The traditional arrangement has CP/M communication software read/write the command, control, status and data ports of an Apple ][ serial interface card indirectly, via a complex transaction with the 6502 command processor. It is common for a terminal program to lose data when the serial port is operating any faster than 2400 bits per second. File transfers, however, can operate at significantly higher speeds.
There have been a few attempts to improve the serial performance through improved device drivers which use interrupt-driven I/O and maintain a receive FIFO on the Apple ][ side of the system. I don't know how widely available these were or are and I haven't yet gained the skill and confidence needed to try them myself. The machine-specific overlay for such a system has to send commands to the 6502 device driver handling the serial port.
Personal Computer Products, Inc. (PCPI) had planned for making expansion of the AppliCard possible. Ray Klein, the AppliCard's designer, designed and built a few serial I/O expansion devices that interfaced directly to the AppliCard, but very few of these cards were built and are thus virtually unheard-of today.
Ever since I learned of the existence of the ``Klein SIO,'' I wanted one. However, I knew that I'd never be able to find one, so I'd have to build one of my own. With a little bit of study, scrounging for documentation and a lot of confidence-building, I finally managed to do just that.
The SIO expansion device I designed and built was inspired by the ``Klein SIO.'' Considering that I've never used or even seen one, how can I make this claim? I managed to come across the IMP and MODEM 740 overlays for the ``Klein SIO'' on the former SIMTEL-20 FTP site. They are still available on `oak.oakland.edu' in the CP/M archives. The filename is `PCPI-SIO.LBR'. Reading these overlays told me nearly everything about how the ``Klein SIO'' was implemented.
To begin with, my board, like the ``Klein SIO,'' requires that a Z80 CTC be present on the AppliCard. If you were wondering what goes in that empty 28-pin DIP socket near the top of your AppliCard, it's the Z80 CTC.
I based my design on the Z80 SIO/0 for two reasons. First, I happened to have a couple of SIO/0 chips on hand. Second, I could replace them with the Z80 DART chip which has the identical pin out (except that the SIO/0's SYNCH* lines are re-labeled as the DART's RI* lines) they are programmed identically for asynchronous I/O. The DART lacks synchronous I/O capability.
Any of the Z80 SIO chips (SIO/0/1/2) may be used, but the accompanying schematic will have to be altered to reflect the pinout of the particular variant used. The SIO/3/4 could also be used if you have facilities for working with QFP or PCC packages, respectively. (As it turned out, I ended up using the DART chip since I damaged both of my SIO/0's when I was building the experimental circuit on my breadboard.)
The bit-rate clock is provided by a 1.8432 MHz clock implemented as shown on the schematic. A sealed oscillator unit could be used, but I used the parts most readily available. (The ``Klein SIO'', in contrast, derived its bit-rate clock by dividing the system clock (6 MHz) by two.) The output of this clock drives the CLK/TRG inputs of Z80 CTC channel 0 and channel 1. The ZC/TO outputs of the CTC supply the actual bit-rate clock to the SIO transmit/receive clock inputs. By programming the CTC with appropriate time constants, bit rates from 50 to 115,200bps may be obtained.
The SIO chip is addressed as I/O at port addresses FCh-FFh. The AppliCard provides an I/O select signal (CS7* on schematic) decoded for addresses E0h-FFh. The decoding is completed by one section of a 74LS10 triple three-input NAND gate driven by address lines A2-A4. CS7* and the output of the NAND gate are combined using one section of a 74LS32 quad 2-input OR gate to provide the SIO CE* signal. Address line A1 selects which channel (A or B) of the SIO is addressed; A0 selects which register (command or data) of the SIO channel is addressed.
The only other signals that I think bear explanation are the CHAINOUT signal and the CASOUT*/CAS* signals. Quite simply, CHAINOUT is the IEO (Interrupt Enable Out) signal of the Z80 CTC installed on the AppliCard. It should, naturally, be connected to the IEI (Interrupt Enable In) signal of the SIO so the SIO can properly participate in Z80 mode-2 vectored interrupts.
CASOUT* is the output of the DRAM CAS*-generation logic. The CAS* signal, then is the CAS* input of the on-board DRAM array. In a standard 64K AppliCard, a shorting block (or jumper) is installed across pins 13 and 38 of the P2 expansion connector to complete the signal path. Any expansion device connected to P2 must maintain this connection unless the RAM expansion unit known as the ``AppliDisk'' is installed. As noted on the schematic, CASOUT* and CAS* should not be connected if an AppliDisk is being used.
The AppliCard's on-board Z80 CTC is addressed as I/O at port addresses 80h-83h. Due to partial decoding, the CTC channel control ports repeat throughout the 80h-9Fh address space. The address assignments are as follows:
Address Function
------- ---------------------------------------------
80h CTC channel 0 (SIO chan. A bit rate)
81h CTC channel 1 (SIO chan. B bit rate)
82h CTC channel 2 (unused)
83h CTC channel 3 (Apple ][ Z80 mode 2 interrupt)
Programming information for the Z80 CTC can be found in the Z80 family data books.
The Z80 SIO (or DART) registers are accessed as follows:
Address Function
------- ------------------------------
FCh SIO channel A data register
FDh SIO channel A control register
FEh SIO channel B data register
FFh SIO channel B control register
Programming information for the Z80 SIO/x and DART can be found in the Z80 family data books.
The SIO expansion may operate using either polled I/O or using Z80 mode 2 interrupts. In the AppliCard system, interrupt vectors begin at FF80h. Memory addresses FF80h-FFBFh are available for interrupt service routine (ISR) addresses. The first 4 vector locations (FF80h-FF87h) are nominally reserved for the on-board CTC, although the standard system software doesn't implement CTC interrupts.
I built an experimental version of the SIO expansion on a breadboard and connected it to ``P2'' of my AppliCard with a piece of 50-line ribbon cable. A 2x25-pin IDC female header was attached to one end of the cable. On the other end, I attached 4 3M-brand 14-pin IDC DIP header connectors which I had trimmed until they fit exactly side-by-side on the 50-line ribbon cable (and in the breadboard pin holes).
Testing began by writing some code fragments using DDT's mini assembler which initialize the CTC and SIO and read and write simple data from/to the SIO command and data registers. For feedback, I had a DMM, a simple logic probe and a modem. Seems every time I turned around, I uncovered yet another wiring error. (That's how I ruined my 2 SIO/0's--I accidentally got the SIO's D0 line plugged into +12V!)
Once satisfied that everything was working properly, I whipped up a quick overlay for QTERM to use the SIO in polled I/O mode. This was very easy to do since the addition of the SIO expansion made the AppliCard look like any other system which uses the Z80 SIO and CTC chips. I simply took the overlay for my Davidge DSB 4/6 single-board computer, changed the port addresses for the SIO and CTC, re-assembled it and patched it into QTERM. A Kaypro overlay might also be a good starting point.
Once convinced that my experimental version was working, I wire- wrapped a prototype on a 4-inch by 3-inch piece of phenolic board. The only sticky problem I had to solve was how to attach the SIO board to the ``P2'' expansion connector. I managed to find some SIP wire-wrap sockets and placed two 25-pin strips in adjacent rows across the phenolic board. I made sure to only wrap one level on these pins. The excess length allowed me to use 2x25 female IDC headers and a short piece of 50-line ribbon cable to connect the SIO board to the AppliCard. I used the same approach to construct connector ``J2'' shown on the schematic.
During the course of extended testing, I discovered that some of my AppliCards can't cope with interrupts from the SIO board. I noticed that boards with serial numbers 13781, 800, and 580 would hang after a few characters were received. Boards with serial numbers 16582 and higher worked just fine with interrupt- driven I/O. (#16582 was the AppliCard I used during all my testing.) If any AppliCard users build a similar SIO board, I'd like to know how your system performs.
In any event, all boards worked fabulously using polled I/O. The biggest aid is that my overlays for QTERM and ZMP implement RTS/CTS handshaking and a 256-byte FIFO buffer in both polled and interrupt versions. I can run at 38400bps DTE speed using a 4MHz Applicard with polled I/O. 57600bps is easily attainable using a 6MHz AppliCard and interrupt-driven I/O. There is no character loss when using my USR Sportster 14400 modem.
I also discovered some interesting traits of the Z80 DART chip. If any data are transmitted/received prior to programming an interrupt vector (as in polled I/O), the DART must be power- cycled before it can be used in interrupt-driven I/O mode. If the RESET* line is asserted (system reset) at any time after initial power-up, the DART will not operate in interrupt-driven I/O mode. In both cases, the DART will appear to have generated an interrupt (IE0 line negated), but it never asserts the INT* line. In addition, if an interrupt vector is programmed but the DART is used in polled I/O mode, the interrupt vector cannot be re-programmed.
I couldn't find these traits mentioned in my Zilog documentation, so I don't know if they are peculiar to the DART or if the SIO also exhibits them, or if they are a side-effect of my SIO board implementation. I would appreciate feedback from anyone with more extensive experience designing with and using these parts.
The schematic indicates a real-time clock/RAM chip. That is what I had in mind to fill up the extra space the wire-wrap prototype has on the board. I have a Motorola MC146818A that I scavenged out of a dead GRiD Systems '286 laptop machine, but lately I've had my eye on a Dallas Semiconductor DS17887-5 clock/RAM module. If I had a source for the Dallas part, I'd be further inclined to complete that addition to the board.
If I had the skill and facilities, I'd like to try producing a PCB for the SIO board. That would make it much neater for installation. A big help would be to find 2x5 and 2x25 female wire-wrap header connectors that would let the board plug directly onto the AppliCard expansion connectors and pass the expansion bus on to further devices.
This was the first hardware project I've designed, built, tested, and programmed entirely by myself. It wasn't until completing classes in interfacing and system design this past spring that I had the knowledge, skill, competence and, most importantly, the confidence to tackle a project like this.
Again, if any AppliCard users build or have built a similar SIO device, I'd like to hear from them about how well it worked.
John D. Baker, KN5UKS, 3 September 1995.
For bit rates of 450bps to 115,200bps, the 1.8432 MHz clock is selected by programming the CTC for counter mode and loading the appropriate time constant as follows:
Bit Rate CTC Time Constant (SIO in x16 mode)
-------- -----------------------------------
450 0 (=256)
600 192
710 162 (0.16% error)
900 128
1200 96
1800 64
2400 48
3600 32
4800 24
7200 16
9600 12
14400 8
19200 6
38400 3
57600 2
115200 1
For bit rates below 450, the bit rate is derived from the system clock divided by 16 or 256 by programming the CTC for timer mode with the desired prescaler value (16 or 256) and loading the appropriate time constant, derived by the formula:
clock speed (Hz)
tc = ----------------
16 * ps * bps
where:
tc = CTC time constant
ps = prescaler value (16 or 256)
bps = bit rate in bits per second
For example, with a 6 MHz clock, a prescaler value of 16, the time constant for 300 bps is:
6 * 10^6
tc = ------------- = 78.125
16 * 16 * 300
which gives:
tc = 78 = 4Eh (0.16% error)
It should be noted that all of the above time constant tables and calculations assume that the Z80 SIO is programmed in ``x16'' mode. That is, the transmit and receive clocks supplied to the SIO are sixteen times the desired bit rate. The SIO may also be programmed to ``x1'', ``x32'' or ``x64'' modes, meaning the transmit/receive clocks are 1, 32 or 64 times the desired bit rate, respectively. The maximum data rate of the Z80 SIO or DART is one-fifth the speed of the supplied system clock (CLK).
The CTC time constant formula can then be generalized as:
source clock (Hz)
tc = -----------------
scm * ps * bps
where:
tc = CTC time constant
scm = SIO Clock Mode (1, 16, 32, 64)
ps = CTC prescaler value (1 for counter mode,
16 or 256 for timer mode)
bps = bit rate
Using the 1.8432 MHz clock (CTC in counter mode), with the SIO in ``x32'' mode, the time constant for 300 bps is calculated as:
1.8432 * 10^6
tc = ------------- = 192 (exactly) = C0h.
32 * 1 * 300
By choosing appropriate combinations of SIO clock mode, clock source and prescaler value, the time constant to generate reasonably accurate standard bit rates may be found by the preceeding formulas.
© 1995 John D. Baker, jdbaker@mylinuxisp.com
Transmission of this document, in whole or in part, via the
Microsoft Network requires license. License is available to Microsoft
Corporation for an annual fee of US$15,000 plus US$5.00 per machine
connected to the Microsoft Network. Appearance of this document on
any machine so connected constitutes agreement to these terms. ``Appearance''
means that this document has been transferred to local storage of said
connected machine, regardless of whether its contents are rendered on
a display device. Please send notice of violation of this licence
agreement to John D. Baker at the address above.