SLPRG.TXT

(35 KB) Pobierz
SwiftLink-232 Application Notes
Revision T v1.0.0


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 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 functions as their 
software counterparts. You may need to make a few changes in your 
program to accommodate the differences.


Buffers

Bytes received are placed in "circular" or "ring" buffers by the sample 
receive 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 
frees many zero page locations, which could improve performance of 
pointers to larger 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 "minimum 
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 in the transmit buffer follows 
the sample interrupt handler.

Using a transmit buffer allows your main program to perform other tasks 
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 a 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 wastes 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).


ACIA Registers 

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

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 the 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 then be 
placed in this register.

Status Register ($DE01)

This register has dual functionality: it show the status of 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 (Figure 8), 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 ACIA's, 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 echoes of commands would not appear on your 
user's screen. We wanted the receiver active at all times. We also 
wanted to give 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 a null-modem cable possibly).

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 is set 
(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 these features to your code might be a good idea.

Command Register ($DE02)

The Command register (Fi...
Zgłoś jeśli naruszono regulamin