                     SwiftLink-232 Application Notes

                             (version 1.1)

This information is made available from a paper document published by CMD,
with CMD's express written permission.  [This version includes a couple of
grammatical corrections and minor changes, plus, the source code has been
debugged and extended.]

1. INTRODUCTION

The SwiftLink-232 ACIA cartridge replaces the Commodore Kernal RS-232 routines
with a hardware chip.  The chip handles all the bit-level processing now done
in software by the Commodore Kernal.  The ACIA may be accessed by polling
certain memory locations in the I/O block ($D000 - $DFFF) or through
interrupts.  The ACIA may be programmed to generate interrupts in the
following situations:

1) when a byte of data is received
2) when a byte of data may be transmitted (i.e., the data register is empty)
3) both (1) and (2)
4) never

The sample code below sets up the ACIA to generate an interrupt each time a
byte of data is received.  For transmitting, two techniques are shown.  The
first technique consists of an interrupt handler which enables transmit
interrupts when there are bytes ready to be sent from a transmit buffer.
There is a separate routine given that manages the transmit buffer.  In the
second technique, which can be found at the very end of the sample code,
neither a transmit buffer or transmit interrupts are used.  Instead, bytes of
data are sent to the ACIA directly as they are generated by the terminal
program.

NOTE: The ACIA will _always_ generate an interrupt when a change of state
occurs on either the DCD or DSR line (unless the lines are not connected in
the device's cable).

The 6551 ACIA was chosen for several reasons, including the low cost and
compatibility with other Commodore (MOS) integrated circuits.  Commodore used
the 6551 as a model for the Kernal software.  Control, Command, and Status
registers in the Kernal routines partially mimic their hardware counterparts
in the ACIA.

NOTE: If you're using the Kernal software registers in your program, be sure
to review the enclosed 6551 data sheet carefully.  Several of the hardware-
register locations do _not_ perform the same function as their software
counterparts.  You may need to make a few changes in your program to
accommodate the differences.

2. BUFFERS

Bytes received are placed in "circular" or "ring" buffers by the sample
routine below, and also by the first sample transmit routine.  To keep things
similar to the Kernal RS-232 implementation, we've shown 256-byte buffers.
You may want to use larger buffers for file transfers or to allow more
screen-processing time.  Bypassing the Kernal routines free many zero-page
locations, which could improve performance of pointers to large buffers.

If your program already directly manipulates the Kernal RS-232 buffers, you'll
find it very easy to adapt to the ACIA.  If you use calls to the Kernal RS-232
file routines instead, you'll need to implement lower-level code to get and
store buffer data.

Briefly, each buffer has a "head" and "tail" pointer.  The head points to the
next byte to be removed from the buffer.  The tail points to the next free
location in which to store a byte.  If the head and tail both point to the
same location, the buffer is empty.  If (tail+1)==head, the buffer is full.

The interrupt handler described below will place received bytes at the tail of
the receive buffer.  Your program should monitor the buffer, either by
comparing the head and tail pointers (as the Commodore Kernal routines do), or
by maintaining a byte count through the interrupt handler (as the attached
sample does).  When bytes are available, your program can process them, move
the head pointer to the next character, and decrement the counter if you use
one.

You should send a "Ctrl-S" (ASCII 19) to the host when the buffer is nearing
capacity.  At higher baud rates, this "maximum size" point may need to be
lowered.  We found 50 to 100 bytes worked fairly well at 9600 baud.  You can
probably do things more efficiently (we were using a _very_ rough
implementation) and set a higher maximum size.  At some "maximum size", a
"Ctrl-Q" (ASCII 17) can be sent to the host to resume transmission.

To transmit a byte using the logic of the first transmit routine below, first
make sure that the transmit buffer isn't full.  Then store the byte at the
tail of the transmit buffer, point the tail to the next available location,
and increment the transmit buffer counter (if used).

The 6551 transmit interrupt occurs when the transmit register is empty and
available for transmitting another byte.  Unless there are bytes to transmit,
this creates unnecessary interrupts and wastes a lot of time.  So, when the
last byte is removed from the buffer, the interrupt handler in the first
transmit routine below disables transmit interrupts.

Your program's code that stuffs new bytes into the transmit buffer must
re-enable transmit interrupts, or your bytes may never be sent.  A model for a
main code routine for placing bytes into the transmit buffer follows the
sample interrupt handler.

Using a transmit buffer allows  your main program to perform other takes while
the NMI interrupt routine takes care of sending bytes to the ACIA.  If the
buffer has more than a few characters, however, you may find that most of the
processor time is spent servicing the interrupt.  Since the ACIA generates NMI
interrupts, you can't "mask" them from the processor, and you may have timing
difficulties in your program.

One solution is to eliminate the transmit buffer completely.  Your program can
decide when to send each byte and perform any other necessary tasks in between
bytes as needed.  A model for the main-code routine for transmitting bytes
without a transmit buffer is also shown following the sample interrupt-handler
code.  Feedback from developers to date is that many of them have better luck
_not_ using transmit interrupts or a transmit buffer.

Although it's possible to eliminate the receive buffer also, we strongly
advise that you don't.  The host computer, not your program, decides when
a new byte will arrive.  Polling the ACIA for received bytes instead of
using an interrupt-driven buffer just waste's your program's time and
risks missing data.

For a thorough discussion of the use of buffers, the Kernal RS-232 routines,
and the Commodore NMI handler, see "COMPUTE!'s VIC-20 and Commodore 64 Tool
Kit: Kernal", by Dan Heeb (COMPUTE! Books) and "What's Really Inside the
Commodore 64", by Milton Bathurst (distributed in the US by Schnedler
Systems).

3. ACIA REGISTERS

The four ACIA registers are explained in detail in the enclosed data sheets.
The default location for them in our cartridge is address $DE00--$DE03
(56832--56836).

3.1. DATA REGISTER ($DE00)

This register has dual functionality: it is used to receive and transmit all
data bytes (i.e., it is a read/write register).

Data received by the ACIA is placed in this register.  If receive interrupts
are enabled, an interrupt will be generated when all bits for a received
byte have been assembled and the byte is ready to read.

Transmit interrupts, if enabled, are generated when this register is empty
(available for transmitting).  A byte to be transmitted can be placed in this
register.

3.2. STATUS REGISTER ($DE01)

This register has dual functionality: it shows the various ACIA settings when
read, but when written to (data = anything [i.e., don't care]), this register
triggers a reset of the chip.

As the enclosed data sheet shows, the ACIA uses bits in this register to
indicate data flow and errors.

If the ACIA generates an interrupt, bit #7 is set.  There are four possible
sources of interrupts:

1) receive (if programmed)
2) transmit (if programmed)
3) if a connected device changes the state of the DCD line
4) if a connected device changes the state of the DSR line

Some programmers have reported problems with using bit #7 to verify ACIA
interrupts.  At 9600 bps and higher, the ACIA generates interrupts properly,
and bits #3--#6 (described below) are set to reflect the cause of the
interrupt, as they should.  But, bit #7 is not consistently set.  At speeds
under 9600 bps, bit #7 seems to work as designed.  To avoid any difficulties,
the sample code below ignores bit #7 and tests the four interrupt source bits
directly.

Bit #5 indicates the status of the DSR line connected to the RS-232 device
(modem, printer, etc.), while bit #6 indicates the status of the DCD line.
NOTE: The function of these two bits is _reversed_ from the standard
implementation.  Unlike many ACIAs, the 6551 was designed to use the DCD
(Data Carrier Detect) signal from the modem to activate the receiver section
of the chip.  If DCD is inactive (no carrier detected), the modem messages
and echos of commands would not appear on the user's screen.  We wanted the
receiver active at all times.  We also wanted to give the you access to the
DCD signal from the modem.  So, we exchanged the DCD and DSR signals at the
ACIA.  Both lines are pulled active internally by the cartridge if left
unconnected by the user (i.e., in an null-modem cable possibility).

Bit #4 is set if the transmit register is empty.  Your program must monitor
this bit and not write to the data register until the bit i sset (see the
sample XMIT code below).

Bit #3 is set if the receive register is full.

Bits #2, #1, and #0, when set, indicate overrun, framing, and parity errors in
received bytes.  The next data byte received erases the error information for
the preceding byte.  If you wish to use these bits, store them for processing
by your program.  The sample code below does not implement any error checking,
but the Kernal software routines do, so adding features to your code might be
a good idea.

3.3. COMMAND REGISTER ($DE02)

The Command Register control parity checking, echo mode, and transmit/receive
interrupts.  It is a read/write register, but reading the register simply
tells you what the settings of the various parameters are.

You use bits #7, #6, and #5 to choose the parity checking desired.

Bit #4 should normally be cleared (i.e., no echo)

Bits #3 and #2 should reflect whether or not you are using transmit
interrupts, and if so, what kind.  In the first sample transmit routine below,
bit #3 is set and bit #2 is cleared to disable transmit interrupts (with RTS
low [active]) on startup.  However, when a byte is placed in the transmit
buffer, bit #3 is cleared and bit #2 is set to enable transmit interrupts
(with RTS low).  When all bytes in the buffer have been transmitted, the
interrupt handler disables transmit interrupts.  NOTE: If you are connected to
a RS-232 device that uses CTS/RTS handshaking, you can tell the device to stop
temporarily by bringing RTS high (inactive): clear both bits #2 and #3.

Bit #1 should reflect whether or not you are using receive interrupts.  In
the sample code below, it is set to enable receive interrupts.

Bit #0 acts as a "master control switch" for all interrupts on the chip
itself.  It _must_ be set to enable any interrupts -- if it is cleared, all
interrupts are turned off and the receiver section of the chip is disabled.
This bit also pulls the DTR line low to enable communication with the
connected RS-232 device.  Clearing this bit causes most Hayes-compatible
modems to hang up (by bringing DTR high).  This bit should be cleared when a
session is over and the user exits the terminal program to insure that no
spurious interrupts are generated.  One fairly elegant way to do this is to
perform a software reset of the chip (writing any value to the Status
register).

NOTE: In the figures on the 6551 data sheet, there are small charts at the
bottom of each of the labelled "Hardware Reset/Program Reset".  These charts
indicate what values the bits of these registers contain after a hardware
reset (like toggling the computer's power) and a program reset (a write to the
Status register).

3.4. CONTROL REGISTER ($DE03)

You use this register to control the number of stop bits, the word length,
switch on the internal baud-rate generator, and set the baud rate.  It is a
read/write register, but reading the register simply tells you what the
various parameters are.  See the figure in the data sheet for a complete list
of parameters.

Be sure that bit #4, the "clock source" bit, is always set to use the on-chip
crystal-controlled baud-rate generator.

You use the other bits to choose the baud rate, word length, and number of
stop bits.  Note that our cartridge uses a double-speed crystal, so values
given on the data sheet are doubled [this is how they are shown below] (the
minimum speed is 100 bps and the maximum speed is 38,400 bps).

4. ACIA HARDWARE INTERFACING

The ACIA is mounted on a circuit board designed to plug into the expansion
(cartridge) port.  The board is housed in a cartridge shell with a male DB-9
connector at the rear.  The "IBM(R) PC/AT(TM) standard" DB-9 RS-232 pinout is
implemented.  Commercial DB-9 to DB-25 patch cords are readily available, and
are sold by us as well.

Eight of the nine lines from the AT serial port are implemented: TxD, RxD,
DTR, DSR, RTS, CTS, DCD, & GND.  RI (Ring Indicator) is not implemented
because the 6551 does not have a pin to handle it.  CTS and RTS are not
normally used by 2400 bps or slower Hayes-compatible modems, but these lines
are being used by several newer, faster modems (MNP modems in particular).
Note that although CTS is connected to the 6551, there is no way to monitor
what state it is -- the value does not appear in any register.  The 6551
handles CTS automatically: if it is pulled high (inactive) by the connected
RS-232 device, the 6551 stops transmitting (clears the "transmit data register
empty" bit [#4] in the status register).

The output signals are standard RS-232 level compatible.  We've tested units
with several commercial modems and with various computers using null-modem
cables up to 38,400 bps without difficulties.  In addition, there are pull-up
resistors on three of the four input lines (DCD, DSR, CTS) so that if these
pins are not connected in a cable, those three lines will pull to the active
state.  For example, if you happen to use a cable that is missing the DCD
line, the pull-up resistor will pull the line active, so that bit #6 in the
status register would be cleared (DCD is active low).

An on-board crystal provides the baud rate clock signal, with a maximum of
38.4 Kbaud, because we are using a double-speed crystal.  If possible, test
your program at 38.4 Kbaud as well as lower baud rates.  Users may find this
helpful for local file transfers using the C-64/C-128 as a dumb terminal on
larger systems.  And, after all, low-cost 28.8 Kb modems for the masses are
just around the corner.

Default decoding for the ACIA addresses is done by the I/O #1 line (pin 7) on
the cartridge port.  This line is infrequently used on either the C-64 or
C-128 and should allow compatibility with most other cartridge products,
including the REU.  The circuit board also has pads for users with special
needs to change the decoding to I/O #2 (pin 10).  This change moves the ACIA
base address to $DF00, making it incompatible with the REU.

C-128 users may also elect to decode the ACIA at $D700 (this is a SID-chip
mirror on the C-64).  Since a $D700 decoding line is not available at the
expansion port, the user would need to run a clip lead into the computer and
connect to pin 12 of U3.  [NOTE: this paragraph originally read "pin 12 of
U2 (a 74LS138)", but I was told that is should be changed.  I don't know
myself which is correct --CSB].  We have tried this and it works.  $D700 is
an especially attractive location for C-128 BBS authors, because putting the
SwiftLink there will free up the other two memory slots for devices that
many BBS sysops use: IEEE and hard-drive interfaces.

Although we anticipate relatively few people changing ACIA decoding, you
should allow your software to work with a SwiftLink at any of the three
locations.  You could either (1) test for the ACIA automatically by writing a
value to the control register and then attempting to read it back or (2)
provide a user-configurable switch/poke/menu option.

The Z80 CPU used for CP/M mode in the C-128 is not connected to the NMI line,
which poses a problem since the cleanest software interface for C-64/C-128-
mode programming is with this interrupt.  We have added a switch to allow the
ACIA interrupt to be connected to either NMI or IRQ, which the Z80 does use.
The user can move this switch without opening the cartridge.

5. SAMPLE CODE

This section has been translated into ACE-assembler format.  Cut on the dotted
lines to extract the code, and assemble it using the ACE assembler (ACE is a
public-domain program).  This program will work on both the C64 and C128.
To use from BASIC:

LOAD"SAMPLE",8,1
SYS8192

It is a very simple terminal program.  Press the STOP key to exit from it.

%%%---8<---cut-here---8<---%%%
;Sample NMI interrupt handler for 6551 ACIA on Commodore 64/128

;(c) 1990 by Noel Nyman, Kent Sullivan, Brian Minugh,
;Geoduck Development Systems, and Dr. Evil Labs.

;    ---=== EQUATES ===---

base      =    $DE00    ;base ACIA address
data      =    base
status    =    base+1
command   =    base+2
control   =    base+3

;Using the ACIA frees many addresses in zero page normally used by
;Kernel RS-232 routines.  The addresses for the buffer pointers were
;chosen arbitrarily.  The buffer vector addresses are those used by
;the Kernal routines.

rhead     =   $A7      ;pointer to next byte to be removed from
                       ;receive buffer
rtail     =   $A8      ;pointer to location to store next byte received
rbuff     =   $F7      ;receive-buffer vector

thead     =   $A9      ;pointer to next byte to be removed from
                       ;transmit buffer
ttail     =   $AA      ;pointer to location to store next byte
                       ;in transmit buffer
tbuff     =   $F9      ;transmit buffer

xmitcount =   $AB      ;count of bytes remaining in transmit (xmit) buffer
recvcount =   $B4      ;count of bytes remaining in receive buffer

errors    =   $B5      ;DSR, DCD, and received data errors information

xmiton    =   $B6      ;storage location for model of command register
                       ;which turn both receive and transmit interrupts on
xmitoff   =   $BD      ;storage location for model of command register
                       ;which turns the receive interrupt on and the
                       ;transmit interrupts off

NMINV     =   $0318    ;Commodore Non-Maskable Interrupt vector
OLDVEC    =   $03fe    ;innocuous location to store old NMI vector (two bytes)

;    ---=== INITIALIZATION ===---

;Call the following code as part of system initialization.

;clear all buffer pointers, buffer counters, and errors location

      org   $2000      ;change to suit your needs
      lda   #$00
      sta   rhead
      sta   rtail
      sta   thead
      sta   ttail

      sta   xmitcount
      sta   recvcount
      sta   errors

;store the addresses of the buffers in the zero-page vectors

      lda   #<TRANSMIT_BUFFER
      sta   tbuff
      lda   #>TRANSMIT_BUFFER
      sta   tbuff + 1

      lda   #<RECEIVE_BUFFER
      sta   rbuff
      lda   #>RECEIVE_BUFFER
      sta   rbuff + 1

;the next four instructions initialize the ACIA to arbitrary values.
;These could be program defaults, or replaced by code that picks up
;the user's requirements for baud rate, parity, etc.

;The ACIA "control" register controls stop bits, word length, the
;choice of internal or external baud-rate generator, and the baud
;rate when the internal generator is used.  The value below sets the
;ACIA for one stop bit, eight-bit word length, and 4800 baud using the
;internal generator.
;             .------------------------- 0 = one stop bit
;             :
;             :.-------------------- word length, bits 6-7
;             ::.------------------- 00 = eight-bit word
;             :::
;             :::.------------- clock source, 1 = internal generator
;             ::::
;             :::: .----- baud
;             :::: :.---- rate
;             :::: ::.--- bits   ;1010 == 4800 baud, change to what you want
;             :::: :::.-- 0-3
      lda   #%0001_1010
      sta   control

;The ACIA "command" register controls the parity, echo mode, transmit and
;receive interrupt enabling, hardware "BRK", and (indirectly) the "RTS"
;and "DTR" lines.  The value below sets the ACIA for no parity check,
;no echo, disables transmit interrupts, and enables receive interrupts
;(RTS and DTR low).
;             .------------------------- parity control,
;             :.------------------------ bits 5-7
;             ::.----------------------- 000 = no parity
;             :::
;             :::.------------------- echo mode, 0 = normal (no echo)
;             ::::
;             :::: .----------- transmit interrupt control, bits 2-3
;             :::: :.---------- 10 = xmit interrupt off, RTS low
;             :::: ::
;             :::: ::.------ receive interrupt control, 0 = enabled
;             :::: :::
;             :::: :::.--- DTR control, 1=DTR low
      lda   #%0000_1001
      sta   command

;Besides initialization, also call the following code whenever the user
;changes parity of echo mode.
;It creates the "xmitoff" and "xmiton" models used by the interrupt
;handler and main-program transmit routine to control the ACIA
;interrupt enabling.  If you don't change the models' parity bits,
;you'll revert to "default" parity on the next NMI.

                        ;initialize with transmit interrupts off since
                        ;buffer will be empty

      sta   xmitoff     ;store as a model for future use
      and   #%1111_0000 ;mask off interrupt bits, keep parity/echo bits
      ora   #%0000_0101 ;and set bits to enable both transmit and
                        ;receive interrupts
      sta   xmiton      ;store also for future use

;The standard NMI routine tests th <RESTORE> key, CIA #2, and checks
;for the presence of an autostart cartridge.

;You can safely bypass the normal routine unless:
;       *  you want to keep the user port active
;       *  you want to use the TOD clock in CIA #2
;       *  you want to detect an autostart cartridge
;       *  you want to detect the RESTOR key
;
;If you need any of these functions, you can wedge the ACIA
;interrupt handler in ahead of the Kernal routines.  It's probably
;safer to replicate in your own program only the Kernal NMI functions
;that you need.  We'll illustrate bypassing all Kernal tests.

;BE SURE THE "NEWNMI" ROUTINE IS IN PLACE BEFORE EXITING THIS CODE!
;A "stray" NMI that occurs after the vector is changed to NEWNMI's address
;will probably cause a system crash if NEWNMI isn't there.  Also, it would
;be best to initialize the ACIA to a "no interrupts" state until the
;new vector is stored.  Although a power-on reset should disable all
;ACIA interrupts, it pays to be sure.

;If the user turns the modem off and on, an interrupt will probably be
;generated.  At worst, this may leave a stray character in teh receive
;buffer, unless you don't have NEWNMI in place.

NEWVEC:
      sei               ;A stray IRQ shouldn't cause any problems
                        ;while we're changing the NMI vector, but
                        ;why take chances?

;If you want all the normal NMI tests to occur after the ACIA check,
;save the old vector.  If you don't need the regular stuff, you can
;skip the next four lines.  Note that the Kernal NMI routine pushes
;the CPU registers to the stack.  If you call it at the normal address,
;you should pop the registers first (see EXITINT below).

      lda   NMINV      ;get low byte of present vector
      sta   OLDVEC     ;and store it for future use
      lda   NMINV+1    ;do the same
      sta   OLDVEC+1   ;with the high byte

                       ;come here from the SEI if you're not saving
                       ;the old vector
      lda   #<NEWNMI   ;get low byte of new NMI routine
      sta   NMINV      ;store in vector
      lda   #>NEWNMI   ;and do the same with
      sta   NMINV+1    ;the high byte

      cli              ;allow IRQs again

;continue initializing your program

;     :::   ::::::     ;program initialization continues
      jmp   TERMINAL   ;go to the example dumb-terminal subroutine

;Save two bytes to store the old vector only if you need it


;    ---=== New NMI Routine Starts Here ===---

;The code below is a simple interrupt patch to control the ACIA.  When
;the ACIA generates an interrupt, this routine examines the status
;register which contains the following data.

;             .---------------------------- high if ACIA caused interrupt;
;             :                             not used in code below
;             :
;             :.------------------------- reflects state of DCD line
;             ::
;             ::.---------------------- reflects state of DSR line
;             :::
;             :::.------------------ high if xmit-data register is empty
;             ::::
;             :::: .--------------- high if receive-data register full
;             :::: :
;             :::: :.----------- high if overrun error
;             :::: ::
;             :::: ::.------- high if framing error
;             :::: :::
;             :::: :::.--- high if parity error
;     status  xxxx_xxxx

NEWNMI:
;     sei              ;the Kernal routine already does this before jumping
                       ;through the NMINV vector
      pha              ;save A register
      txa
      pha              ;save X register
      tya
      pha              ;save Y register

;As discussed above, the ACIA can generate an interrupt from one of four
;different sources.  We'll first check to see if the interrupt was
;caused by the receive register being full (bit #3) or the transmit
;register being empty (bit #4) since these two activities should receive
;priority.  A BEQ (Branch if EQual) tests the status register and branches
;if the interrupt was not caused by the data register.

;Before testing for the source of the interrupt, we'll prevent more
;interrupts from the ACIA by disabling them at the chip.  This prevents
;another NMI from interrupting this one.  (SEI won't work because the
;CPU can't disable non-maskable interrupts).

;At lower baud rates (2400 baud and lower) this may not be necessary.  But,
;it's safe and doesn't take much time, either.

;The same technique should be used in parts of your program where timing
;is critical.  Disk access, for example, uses SEI to mask IRQ interrupts.
;You should turn off the ACIA interrupts during disk access also to prevent
;disk errors and system crashes.

;First, we'll load the status register which contains all the interrupt
;and any received-data error information in the 'A' register.

      lda   status

;Now prevent any more NMIs from the ACIA

      ldx   #%0000_0011   ;disable all interrupts, bring RTS inactive, and
                          ;leave DTR active
      stx   command       ;send to ACIA-- code at end of interrupt handler
                          ;will re-enable interrupts

;Store the status-register data only if needed for error checking.
;The next received byte will clear the error flags.

;     sta   errors        ;only if error checking implemented

      and   #%0001_1000   ;mask out all but transmit and
                          ;receive interrupt indicators

;If you don't use a transmit buffer you can use
;
;     and   #%0000_1000
;
;to test for receive interrupts only and skip the receive test shown
;below.

      beq   TEST_DCD_DSR

;if the 'A' register=0, either the interrupt was not caused by the
;ACIA or the ACIA interrupt was caused by a change in the DCD or
;DSR lines, so we'll branch to check those sources.

;If your program ignores DCD and DSR, you can branch to
;the end of the interrupt handler instead:
;
;     beq   NMIEXIT
;

;Test the status register information to see if a received byte is ready
;If you don't use a transmit buffer, skip the next two instructions.

RECEIVE:                  ;process received byte
      and   #%0000_1000   ;mask all but bit #3
      beq   XMITCHAR      ;if not set, no received byte - if you're using
                          ;a transmit buffer, the interrupt must have been
                          ;caused by transmit.  So, branch to handle.
      lda   data          ;get received byte
      ldy   rtail         ;index to buffer
      sta   (rbuff),y     ;and store it
      inc   rtail         ;move index to next slot
      inc   recvcount     ;increment count of bytes in receive buffer
                          ;(if used by your program)

;Skip the "XMIT" routines below if you decide not to use a transmit buffer.
;In that case, the next code executed starts at TEST_DCD_DSR or NMIEXIT.

;After processing a received byte, this sample code tests for bytes
;in the transmit buffer and sends on if present.  Note that, in this
;sample, receive interrupts take precedence.  You may want to reverse the
;order in your program.

;If the ACIA generated a transmit interrupt and no received byte was
;ready, status bit #4 is already set.  The ACIA is ready to accept
;the byte to be transmitted and we've branched directly to XMITCHAR below.

;If only bit #3 was set on entry to the interrupt handler, the ACIA may have
;been in the process of transmitting the last byte, and there may still be
;characters in the transmit buffer.  We'll check for that now, and send the
;next character if there is one.  Before sending a character to the ACIA to
;be transmitted, we must wait until bit #4 of the status register is set.

XMIT:
      lda   xmitcount     ;if not zero, characters still in buffer
                          ;fall through to process xmit buffer
      beq   TEST_DCD_DSR  ;no characters in buffer-- go to next check
;or
;
;     beq   NMIEXIT
;
;if you don't check DCD or DSR in your program.

XMITBYTE:
      lda   status        ;test bit #4
      and   #%00010000
      beq   TEST_DCD_DSR  ;skip if transmitter still busy

XMITCHAR:                 ;transmit a character
      ldy   thead
      lda   (tbuff),y     ;get character at head of buffer
      sta   data          ;place in ACIA for transmit

                          ;point to next character in buffer
      inc   thead         ;and store new index
      dec   xmitcount     ;subtract one from count of bytes
                          ;in xmit buffer
      lda   xmitcount
      beq   TEST_DCD_DSR
;or
;
;     beq   NMIEXIT
;
;if you don't check DCD or DSR in your program

;If xmitcount decrements to zero, there are no more characters to
;transmit.  The code at NMIEXIT turns ACIA transmit interrupts off.

;If there are more bytes in the buffer, set up the 'A' register with
;the model that turns both transmit and receive interrupts on.  We felt
;that was safer, and not much slower, than EORing bits #3 and #4.  Note
;that the status of the parity/echo bits is preserved in the way "xmiton"
;and "xmitoff" were initialized earlier.

      lda   xmiton        ;model to leave both interrupts enabled

;If you don't use DCD or DSR

      bne   NMICOMMAND    ;branch always to store model in command register

;If your program uses DCD and/or DSR, you'll want to know when the state
;of those lines changes.  You can do that outside the interrupt handler
;by polling the ACIA status register, but if either of the lines changes,
;the chip will generate an NMI anyway.  So, you can let the interrupt
;handler do teh work for you.  The cost is the added time required to
;execute the DCD_DSR code on each NMI.

TEST_DCD_DSR:

;     pha                 ;only if you use a transmit buffer, 'A' holds
                          ;the proper mask to re-enable interrupts on
                          ;the ACIA
;     ::
;     ::                  ;appropriate code here to compare bit #6 (DCD)
;     ::                  ;and/or bit #5 (DSR) with their previous states
;     ::                  ;which you've already stored in memory and take
;     ::                  ;appropriate action
;     ::
;     pla                 ;only if you pushed it at the start of the
                          ;DCD/DSR routine
;     bne   NMICOMMAND    ;'A' holds the xmiton mask if it's not zero,
                          ;implying that we arrived here from xmit routine
                          ;not used if you're not using a transmit buffer.

;If the test for ACIA interrupt failed on entry to the handler, we branch
;directly to here.  If you don't use additional handlers, the RESTORE key
;(for example) will fall through here and have no effect on your program
;or the machine, except for some wasted cycles.

NMIEXIT:
      lda   xmitoff       ;load model to turn transmit interrupts off

;and this line sets the interrupt status to whatever is in the 'A' register.

NMICOMMAND:
      sta   command

;That's all we need for the ACIA interrupt handler.  Since we've pushed the
;CPU registers to the stack, we need to pop them off.  Note that you must
;do this EVEN IF YOU JUMP TO THE KERNAL HANDLER NEXT, since it will push
;them again immediately.  You can skip this step only if you're proceeding
;to a custom handler.

EXITINT:                  ;restore things and exit
      pla                 ;restore 'Y' register
      tay
      pla                 ;restore 'X' register
      tax
      pla                 ;restore 'A' register

;If you want to continue processing the interrupt with the Kernal routines,

      jmp   (OLDVEC)      ;continue processing interrupt with Kernal handler

;Or, if you add your own interrupt routine,

;     jmp   YOURCODE      ;continue with your own handler

;If you use your own routine, or if you don't add anything, BE SURE to do
;this last (C64 only):

;     rti                 ;return from interrupt instruction

;to restore the flags register the CPU pushes to the stack before jumping
;to the Kernal code.  It also returns you to the interrupted part of
;your program
 
;-----------------------------------------------------------------------------
;Sample routine to store a character in the buffer to be transmitted
;by the ACIA.

;(c) 1990 by Noel Nyman, Kent Sullivan, Brian Minugh,
;Geoduck Developmental Systems, and Dr. Evil Labs.

;Assumes the character is in the 'A' register on entry.  Destroys 'Y'--
;push to stack if you need to preserve it.

SENDBYTE:                 ;adds a byte to the xmit buffer and sets
                          ;the ACIA to enable transmit interrupts (the
                          ;interrupt handler will disable them again
                          ;when the buffer is empty)

      ldy   xmitcount     ;count of bytes in transmit buffer
      cpy   #255          ;max buffer size
      beq   NOTHING       ;buffer is full, don't add byte

      ldy   ttail         ;pointer to end of buffer
      sta   (tbuff),y     ;store byte in 'A' at end of buffer
      inc   ttail         ;point to next slot in buffer
      inc   xmitcount     ;and add one to count of bytes in buffer

      lda   xmiton        ;get model for turning on transmit interrupts
      sta   command       ;tell ACIA to do it

      rts                 ;return to your program

NOTHING:
      lda   #$00          ;or whatever flag your program uses to tell that the
                          ;byte was not transmitted
      rts                 ;and return

;Alternative routine to transmit a character from main program when not using
;a transmit buffer.
;
;(c) 1990 by Noel Nyman, Kent Sullivan, Brian Minugh,
;Geoduck Developmental Systems, and Dr. Evil Labs.
;
;Assumes the character to be transmitted is in the 'A' register on entry.
;Destroys 'Y'; push to stack if you need to preserve it.
;
;SENDBYTE:
;     tay                 ;remember byte to be transmitted
;
;TESTACIA:
;     lda   status        ;bit #4 of the status register is set if
;                         ;the ACIA is ready to transmit another byte,
;                         ;even if transmit interrupts are disabled.
;     and   #%0001_0000
;     beq   TESTACIA      ;wait for bit #4 to be set
;     sty   data          ;give byte to ACIA
;     rts

;Sample routine to fetch a character that has been received, from the
;receive buffer.

;by Craig Bruce, 1995, adapted from above

;Will return the character in the 'A' register and the carry flag cleared if
;a character was available.  If no character was available, will return with
;the carry flag set.  Destroys the 'Y' register.

RECVBYTE:                 ;fetches a byte from the receive buffer.
                          ;there is no need to fiddle with any interrupts

      lda   recvcount     ;count of bytes in receive buffer
      beq   RECVEMPTY     ;buffer is empty, indicate to caller

      ldy   rhead         ;pointer to start of buffer
      lda   (rbuff),y     ;fetch byte out of buffer into 'A' register
      inc   rhead         ;point to next slot in buffer
      dec   recvcount     ;and add one to count of bytes in buffer

      clc                 ;indicate that we have a character
      rts                 ;return to your program

RECVEMPTY:
      sec                 ;or whatever flag your program uses to tell that the
                          ;receive buffer was empty
      rts                 ;and return

;-----------------------------------------------------------------------------
;Dumb -- very dumb -- terminal emulator.  Simply polls the receive buffer and
;the keyboard and puts received data to the screen and typed data to the send
;buffer (thus, it assumes a full-duplex, echoing link).  There is no
;PETSCII->ASCII conversion, no cursor, nor any other fancy features.  Press
;STOP to exit.
;
;by Craig Bruce, 1995.

TERMINAL:
      jsr   RECVBYTE      ;see if there is a received byte in the recv buffer
      bcs   TERMTRYSEND   ;if not, continue
      jsr   $FFD2         ;if received byte, print it to the screen (CHROUT)
TERMTRYSEND:
      jsr   $FFE4         ;try to get a character from the keyboard (GETIN)
      cmp   #$00          ;was there a keystroke available?
      beq   TERMINAL      ;no--go back to top of polling loop
      cmp   #$03          ;check for STOP key
      beq   TERMEXIT      ;  exit if pressed
      jsr   SENDBYTE      ;have char--put it into the transmit buffer and then
      jmp   TERMINAL      ;  go back to top of polling loop
TERMEXIT:
      lda   #%0000_0010   ;disable transmitter and receiver and all interrupts
      sta   command
      sei
      lda   OLDVEC        ;restore the NMI vector to its original value
      sta   NMINV
      lda   OLDVEC+1
      sta   NMINV+1
      cli
      rts                 ;exit

TRANSMIT_BUFFER = *+0
RECEIVE_BUFFER  = *+256
%%%---8<---cut-here---8<---%%%

------------------------------------------------------------------------------
              APPENDIX: 6551 ACIA HARDWARE SPECS (DATA SHEET)

                     C= Commodore Semiconductor Group
              a division of Commodore Business Machines, Inc.
 950 Rittenhouse Road, Nornstown, PA 19400 * 215/666-7950 * TWX 510-660-4168
                                (July 1987)

             6551 ASYNCHRONOUS COMMUNICATION INTERFACE ADAPTER

CONCEPT:

The 6551 is an Asynchronous Communication Adapter (ACIA) intended to provide
for interfacing the 6500/6800 microprocessor families to serial communication
data sets and modems.  A unique feature is the inclusion of an on-chip
programmable baud-rate generator, with a crystal being the only external
component required.

FEATURES:

* On-chip baud-rate generator: 15 programmable baud rates derived from a
  standard standard 1.8432 MHz external crystal (50 to 19,200 baud) [these
  rates are doubled in the SwiftLink].

* Programmable interrupt and status register to simplify software design.

* Single +5 volt power supply.

* Serial echo mode.

* False start bit detection.

* 8-bit bi-directional data bus for direct communication with the
  microprocessor.

* External 16x clock input for non-standard baud rates (up to 125 Kbaud).

* Programmable: word lengths; number of stop bits; and parity-bit generation
  and detection.

* Data set and modem control signals provided.

* Parity: (odd, even, none, mark, space).

* Full-duplex or half-duplex operation.

* 5,6,7 and 8-bit transmission.

* 1-MHz, 2-MHz, and 3-MHz operation.

ORDER NUMBER

MXS 6551 ___
 -        |
 |        +---- Frequency range
 |                  Plain = 1 MHz
 |                      A = 2 MHz
 |                      B = 3 MHz
 |
 +----------- Package Designator
                     C = Ceramic
                     P = Plastic

6551 PIN CONFIGURATION

                +---------------+
          GND --| 1          28 |-- R-/W
          CS0 --| 2          27 |-- o2
         /CS1 --| 3          26 |-- /IRQ
         /RES --| 4          25 |-- DB7
          RxC --| 5          24 |-- DB6
        XTAL1 --| 6          23 |-- DB5
        XTAL2 --| 7          22 |-- DB4
         /RTS --| 8          21 |-- DB3
         /CTS --| 9          20 |-- DB2
          TxD --| 10         19 |-- DB1
         /DTR --| 11         18 |-- DB0
          RxD --| 12         17 |-- /DSR
          RS0 --| 13         16 |-- /DCD
          RS1 --| 14         15 |-- Vcc
                +---------------+

BLOCK DIAGRAM                                        +----------+
                                                     | TRANSMIT |
                                                     | CONTROL  |<------- CTS
                                                     +----------+
                                                           |
                                                           v
                               +----------+          +----------+
                               | TRANSMIT |          | TRANSMIT |
                         /|===>|   DATA   |=========>|  SHIFT   |-------> TxD
                         ||    | REGISTER |          | REGISTER |
                         ||    +----------+          +----------+
          +---------+    ||
   o2 --->|         |    ||    +----------+          +----------+
 R-/W --->|  SELECT |    ||====|  STATUS  |          | INTERRUPT|-------> /IRQ
  CS0 --->|   AND   |    ||    | REGISTER |<-------->|   LOGIC  |<------- /DCD
 /CS1 --->| CONTROL |    ||    +----------+          +----------+<------- /DSR
  RS0 --->|  LOGIC  |    ||                
  RS1 --->|         |    ||    +----------+          +----------+
 /RES --->|         |    ||===>| CONTROL  |          | BAUD-RATE|<------> RxC
          +---------+    ||    | REGISTER |          | GENERATOR|<------- XTAL1
                         ||    +----------+          +----------+<------- XTAL2
                         ||
          +---------+    ||    +----------+          +----------+
  DB0 <-->|  DATA-  |    ||    |  RECEIVE |          |  RECEIVE |
  ...     |   BUS   |<===||====|   DATA   |<=========|   SHIFT  |<---+--- RxD
  DB7 <-->| BUFFERS |    ||    | REGISTER |          | REGISTER |    |
          +---------+    ||    +----------+          +-----.----+    |
                         ||                                |         |
                         ||    +----------+          +----------+    |
   LEGEND:               \|===>| COMMAND  |          |  RECEIVE |    |
                               | REGISTER |          |  CONTROL |<---+
   ===> : 8-bit line           +----------+          +----------+
                                  |    |
   ---> : 1-bit line              |    +--------------------------------> /DTR
                                  +-------------------------------------> /RTS

MAXIMUM RATINGS

<not included here>

ELECTRICAL CHARACTERISTICS

<not included here>

POWER DISSIPATION vs TEMPERATURE

<not included here>

TIMING CHARACTERISTICS

<not included here>

INTERFACE SIGNAL DESCRIPTION

/RES (Reset)

During system initialization a low on the /RES input will cause internal
registers to be cleared.

o2 (Input Clock)

The input clock is the system o2 clock and is used to trigger all data
transfers between the system microprocessor and the 6551.

R-/W (Read/Write)

The R-/W is generated by the microprocessor and is used to control the
direction of data transfers.  A high on the R-/W pin allows the processor
to read the data supplied by the 6551.  A low on the R-/W pin allows a write
to the 6551.

/IRQ (Interrupt Request)

The /IRQ pin is an interrupt signal from the interrupt-control logic.  It is
an open drain output, permitting several devices to be connected to the common
/IRQ microprocessor input.  Normally a high level, /IRQ goes low when an
interrupt occurs.

DB0--DB7 (Data Bus)

The DB0--DB7 pins are the eight data lines used for transfer of data between
the processor and the 6551.  These lines are bi-directional and are normally
high-impedance except during Read cycles when selected.

CS0, /CS1 (Chip Selects)

The two chip-select inputs are normally connected to the processor-address
lines either directly or through decoders.  The 6551 is selected when CS0 is
high and /CS1 is low.

RS0, RS1 (Register Selects)

The two register-select lines are normally connected to the processor-address
lines to allow the processor to select the various 6551 internal registers.
The following table indicates the internal register-select coding:

RS1   RS0   WRITE                     READ                    SL-Addr
---   ---   ----------------------    ---------------------   -------
  0     0   Transmit Data Register    Receive Data Register     $DE00
  0     1   Programmed Reset*         Status Register           $DE01
  1     0   Command Register          Command Register          $DE02
  1     1   Control Register          Control Register          $DE03

                * for programmed reset, data is "don't care".

The table shows that only the Command and Control registers are read/write.
The Programmed Reset operation does not cause any data transfer, but is used
to clear the 6551 registers.  The Programmed Reset is slightly different from
the Hardware Reset (/RES) and these differences are described in the
individual register definitions.

ACIA/MODEM INTERFACE SIGNAL DESCRIPTION

XTAL1, XTAL2 (Crystal Pins)

These pins are normally directly connected to the external crystal (1.8432
MHz) used to derive the various baud rates.  Alternatively, an externally
generated clock may be used to drive the XTAL1 pin, in which case the XTAL2
pin must float.  XTAL1 is the input pin for the transmit clock.

TxD (Transmit Data)

The TxD output line is used to transfer serial NRZ (non-return-to-zero) data
to the modem.  The LSB (least-significant bit) of the Transmit Data Register
is the first data bit transmitted and the reate of data transmission is
determined by the baud rate selected.

RxD (Receive Data)

The RxD input line is used to transfer serial NRZ data into the ACIA from the
modem, LSB first.  The receiver data rate is either the programmed baud rate
or the rate of an externally generated receiver clock.  This selection is made
by programming the Control Register.

RxC (Receive Clock)

The RxC is a bi-directional pin which serves as either the receiver 16x clock
input or the receiver 16x clock output.  The latter mode results if the
internal baud rate generator is selected for receiver data clocking.

/RTS (Request to Send)

The /RTS output pin is used to control the modem from the processor.  The
state of the /RTS pin is determined by the contents of the Command Register.

/CTS (Clear to Send)

The /CTS input pin is used to control the transmitter operation.  The enable
state is with /CTS low.  The transmitter is automatically disabled if /CTS is
high.

/DTR (Data Terminal Ready)

The output pin is used to indicate the status of the 6551 to the modem.  A low
of /DTR indicates the 6551 is enabled and a high indicates it is disabled.
The processor controls this pin via bit 0 of the Command Register.

/DSR (Data Set Ready)

The /DSR input pin is used to indicate to the 6551 the status of the modem.  A
low indicates the "ready" state and a high, "not-ready".  /DSR is a high-
impedance input and must not be a no-connect.  If unused, it should be driven
high or low, but not switched.

Note: If Command Register Bit #0 = 1 and a change of state on /DSR occurs,
/IRQ will be set and Status Register Bit #[5] will reflect the new level.  The
state of /DSR does not affect Transmitter operation [but must be low for the
Receiver to operate].  [This statement reflects the SwiftLink implementation].

/DCD (Data Carrier Detect)

The /DCD input pin is used to indicate to the 6551 the status of the carrier-
detect output of the modem.  A low indicates that the modem carrier signal is
present and a high, that it is not.  /DCD, like /DSR, is a high-impedance
input and must not be a no-connect.

Note: If Command Register Bit #0 = 1 and a change of state on /DSR occurs,
/IRQ will be set and Status Register Bit #[6] will reflect the new level.  The
state of /DCD does not affect either Transmitter or Receiver operation.

INTERNAL ORGANIZATION

<not included here>

TRANSMIT AND RECEIVE DATA REGISTERS (SL-Addr: $DE00 / 56832)

These registers are used as temporary data storage for the 6551 Transmit and
Receive circuits.  The Transmit Data Register is characterized as follows:

* Bit 0 is the leading bit to be transmitted.

* Unused data bits are the high-order bits and are "don't care" for
  transmission.

The Receive Data Register is characterized in a similar fashion:

* Bit 0 is the leading bit received.

* Unused data bits are the high-order bits and are "0" for the receiver.

* Parity bits are not contained in the Receive Data Register, but are stripped
  off after being used for external parity checking.  Parity and all unused
  high-order bits are "0".

           Transmit / Receive Data Register
  +-----+-----+-----+-----+-----+-----+-----+-----+
  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
  +-----+-----+-----+-----+-----+-----+-----+-----+
  |                     data                      | 

  The following figure illustrates a single transmitted or received data
  word, for the example of 8 data bits, parity, and 1 stop bit:

  "MARK"____    ________________________________________________________"MARK"
           |    | 0  | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | P  | S  .
           |____|____|____|____|____|____|____|____|____|____|____|
            start                                            parity  stop
             bit                ...data bits...               bit     bit


STATUS REGISTER (SL-Addr: $DE01 / 56833)

The Status Register is used to indicate to the processor the status of various
6551 functions and is outlined here:

                   Command Register
  +-----+-----+-----+-----+-----+-----+-----+-----+
  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
  +-----+-----+-----+-----+-----+-----+-----+-----+
  | irq | dcd | dsr | txr | rxr | ovr | fe  | pe  | 

  +---+
  | 7 |   /IRQ*** : cleared by reading status register
  +---+   --------------------------------------------
    0     No interrupt
    1     Interrupt

  +---+
  | 6 |   /DCD : non-resetable, indicates /DCD status
  +---+   --------------------------------------------
    0     /DCD low
    1     /DCD high

  +---+
  | 5 |   /DSR : non-resetable, indicates /DSR status
  +---+   --------------------------------------------
    0     /DSR low
    1     /DSR high

  +---+
  | 4 |   Transmit Data Register Empty: Cleared by write to Tx Data reg
  +---+   -------------------------------------------------------------
    0     Not empty
    1     Empty

  +---+
  | 3 |   Receive Data Register Full: Cleared by read from Rx Data reg
  +---+   -------------------------------------------------------------
    0     Not full
    1     Full

  +---+
  | 2 |   Overrun*: Self-clearing**
  +---+   -------------------------
    0     No error
    1     Error

  +---+
  | 1 |   Framing Error*: Self-clearing**
  +---+   -------------------------------
    0     No error
    1     Error

  +---+
  | 0 |   Parity Error*: Self-clearing**
  +---+   ------------------------------
    0     No error
    1     Error

  Notes:   * No interrupt generated for these conditions
          ** Cleared automatically after a read of RDR and the next error-
               free receipt of data
         *** Reading status reg. will clear the /IRQ bit except when
               transmit intr. enabled

    7   6   5   4   3   2   1   0
  +---+---+---+---+---+---+---+---+
  | 0 | x | x | 1 | 0 | 0 | 0 | 0 |  After Hardware reset
  +---+---+---+---+---+---+---+---+
  | x | x | x | x | x | 0 | x | x |  After Software reset
  +---+---+---+---+---+---+---+---+


COMMAND REGISTER (SL-Addr: $DE02 / 56834)

The Command Register is used to control specific Transmit/Receive functions
and is shown here:

                   Command Register
  +-----+-----+-----+-----+-----+-----+-----+-----+
  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
  +-----+-----+-----+-----+-----+-----+-----+-----+
  |     parity      | echo|  tx ctrl  | rxi | dtr | 

  +---+---+---+
  | 7 | 6 | 5 |   PARITY CHECK CONTROLS
  +---+---+---+   ----------------------
    x   x   0     parity disabled--no parity bit generated or received
    0   0   1     odd parity receiver and transmitter
    0   1   1     even parity receiver and transmitter
    1   0   1     mark parity transmitted, parity check disabled
    1   1   1     space parity transmitted, parity check disabled

  +---+
  | 4 |   NORMAL/ECHO MODE FOR RECEIVER
  +---+   ------------------------------
    0     Normal
    1     Echo (bits 2 and 3 must be "0")

  +---+---+
  | 3 | 2 |   Tx INTERRUPT    RTS LEVEL    TRANSMITTER
  +---+---+   ------------    ---------    ------------
    0   0       Disabled         High           Off
    0   1       Enabled          Low            On
    1   0       Disabled         Low            On
    1   1       Disabled         Low       Transmit BRK

  +---+
  | 1 |   RECEIVE INTERRUPT ENABLE
  +---+   -------------------------
    0     /IRQ interrupt Enabled from bit 3 of Status Register
    1     /IRQ interrupt Disabled

  +---+
  | 0 |   DATA TERMINAL READY
  +---+   --------------------
    0     Disable Receiver and all interrupts (/DTR high)
    1     Enable Receiver and all interrupts  (/DTR low)

    7   6   5   4   3   2   1   0
  +---+---+---+---+---+---+---+---+
  | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |  After Hardware reset
  +---+---+---+---+---+---+---+---+
  | x | x | x | 0 | 0 | 0 | 0 | 0 |  After Software reset
  +---+---+---+---+---+---+---+---+


CONTROL REGISTER (SL-Addr: $DE03 / 56835 / cpm: 0001xxxx)

The Control Register is used to select the desired mode for the 6551.  The
word length, number of stop bits, and clock controls are all determined
by the Control Register, which is shown here:

                   Control Register
  +-----+-----+-----+-----+-----+-----+-----+-----+
  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
  +-----+-----+-----+-----+-----+-----+-----+-----+
  |stops|  word len | src |       baud rate       |

  +---+
  | 7 |   STOP BITS
  +---+   ----------
    0     1 stop bit
    1     2 stop bits
    1     1 stop bit if word length== 8 bits and parity
              this allows for 9-bit transmission (8 data bits plus parity)
    1     1.5 stop bits if word length== 5 bits and no parity

  +---+---+
  | 6 | 5 |   WORD LENGTH
  +---+---+   ------------
    0   0     8 bits
    0   1     7 bits
    1   0     6 bits
    1   1     5 bits

  +---+
  | 4 |   RECEIVER CLOCK SOURCE
  +---+   ----------
    0     external receiver clock
    1     baud rate generator

  +---+---+---+---+
  | 3 | 2 | 1 | 0 |   BAUD RATE GENERATOR
  +---+---+---+---+   --------------------
    0   0   0   0     16x external clock
    0   0   0   1     100 baud
    0   0   1   0     150 baud
    0   0   1   1     219.84 baud
    0   1   0   0     269.16 baud
    0   1   0   1     300 baud
    0   1   1   0     600 baud
    0   1   1   1     1200 baud
    1   0   0   0     2400 baud
    1   0   0   1     3600 baud
    1   0   1   0     4800 baud
    1   0   1   1     7200 baud
    1   1   0   0     9600 baud
    1   1   0   1     14400 baud
    1   1   1   0     19200 baud
    1   1   1   1     38400 baud

    7   6   5   4   3   2   1   0
  +---+---+---+---+---+---+---+---+
  | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |  After Hardware reset
  +---+---+---+---+---+---+---+---+
  | x | x | x | x | x | x | x | x |  After Software reset
  +---+---+---+---+---+---+---+---+

---END---
