Swiftlink Programming
Swiftlink Programming
by Robin Harbron.
Note: This article originally appeared in Loadstar Letter #46, published in 1997. Thanks to the folks at Loadstar for granting permission for me to post it on my website.
The Swiftlink is yet another cartridge that can be plugged into our trusty computers. It adds a 6551 ACIA to your arsenal of programmable chips. ACIA stands for Asynchronous Communication Interface Adapter, and it does just that: allows your computer to interface with communications devices, such as a modem.
The Commodore 64 wasn’t blessed with an efficient way of communicating with a modem at its birth. This was apparently a cost-cutting measure. A 6551 was partially emulated in the 64’s kernal. But emulation is generally a time-consuming thing. It simulates hardware with software. Instead of being able to send a byte to your communications hardware, and letting the hardware send it out bit-by-bit, the kernal had to do the work itself.
When 300, and then 1200 bps (bits per second) modems were common, this didn’t seem to be such a limitation. But 2400 was a bit of a hurdle for programmers to handle well, and beyond that seemed pretty much impossible. The Swiftlink and other similar cartridges allow us to keep pace with the newer modems. Mine happily sits plugged into my U.S. Robotics 33.6 Faxmodem. 33.6 is short for 33.6K, or 33600 bps, 112 times as fast as my original 64modem!
Unfortunately, it’s a little more difficult to talk to a modem plugged into the cartridge port. BASIC and the Kernal still want to talk to the old user-port modems, so we have to resort to PEEKs and POKEs instead of the more user-friendly OPEN and PRINT# commands.
When first learning to program the Swiftlink (SL from now on), I wrote a short basic program to hack around with. It is pretty much capable of 300 bps with a normal C64, and seems to do a fairly reliable 4800 with the SCPU on. Pretty amazing, to be able to go that fast in BASIC!
I don’t own one yet, but apparently CMD’s new Turbo232, which recently replaced the SL, is backwards compatible. This program should work fine with the T232.
Here’s the program, an extremely simple terminal, interspersed with my comments:
10 POKE 53374,0 : POKE 53366,0 : POKE 53375,0
Enables the SCPU BASIC optimization mode. Not necessary if you don’t have a SCPU, but it should be common practice if you’ll be sharing your programs with those who do have one.
20 SW=56832
This is the base address of the SL. In hex, this is $DE00, one of the two I/O pages that were left free for expansions such as this. You may have $DE00 occupied by another device. If this is the case, $DF00 can be used. Change the value of SW to 57088.
30 POKE SW+2,11
There are four registers in the SL, numbered 0 through 3. These are normally located from $DE00 to $DE03. SW+2 refers to the Command Register. This is used to control how the SL acts while sending and receiving data. Here is the meaning of the various bits:
| 7-5 | Parity Check. This is rarely used nowadays. “None” will suit us just fine, so we’ll store zeros here. |
| 4 | Normal/Echo Mode for Receiver. Normal if set to 0, as we’ll do. If set to 1, bits 2 and 3 must be set to 0, and the receiver will echo, ie. send back whatever it receives. |
| 3-2 | We don’t want interrupts to happen when the SL is ready to send a byte, as we’re going to be using the simple polling method of communicating with the SL. So we’ll store a 10 in these bits. If we did want interrupts to happen whenever the SL was ready to send, we would set a 01 here. |
| 1 | If we want an interrupt to occur whenever a byte arrives to our computer, we set this to 0. We don’t want an interrupt to happen, so we’ll set this to bit to a 1. |
| 0 | If we want to refuse data for a while (perhaps we’ve received more information than we can deal with for a while, or want to do disk access) we can set this bit to 0. We’ll be setting it to 1, to enable receiving. |
40 POKE SW+3,21
SW+3 is the Control Register of the SL. This is used to select the various modes of operation of the 6551. The meanings of the various bits follow:
| 7 | Stop Bits. We’ll set this to 0, meaning we want one stop bit. This is standard practice today. Stop bits are bits that the modems/interfaces use to signal the end of a complete byte. |
| 6-5 | Word Length. Setting this to 00 designates 8 bit word lengths. This simply means that the SL will move a full byte at a time, and this is what we’ll use. 01 is used for 7 bit words, 10 for 6 bit words, and 11 for 5 bit words. These other word lengths are seldom used. |
| 4 | Receiver Clock Source. Setting this to 0 allows one to use an external receiver clock to drive the speed at which the modem operates. This may have uses to some, but we’ll set this bit to 1, to use the internal baud rate generator. |
| 3-0 | Baud Rate Generator. This allows you to set the speed you want the SL to run at. 0101 is 300 bps, and what we’ll use. Each increment is a higher speed. 1000 is 2400 bps, 1100 is 9600 bps, and 1111 is the maximum a SL can do, 38400 bps. |
Do a POKE SW+3,26 if you have a SCPU. This will allow you to operate at 4800 bps.
100 GET A$ 110 IF A$<>"" THEN Z=1
Simply gets the user’s key press, if any. If there is one, set a flag, as we’ll need to send the character out the SL.
120 S=PEEK(SW+1)
SW+1 is the Status Register. This allows you to see the status of the 6551 and it’s functions. Each bit in this register has it’s own meaning:
| 7 | Did an interrupt occur? 0=No, 1=Yes |
| 6 | Shows the status of DCD (Data Carrier Detect). 0=connected, 1=not connected. |
| 5 | Shows the status of DSR (Data Set Ready). 0=low, 1=high. |
| 4 | Transmit Data Register Empty. 0=byte waiting to be sent, 1=empty, available to send a byte. |
| 3 | Receive Data Register Full. 0=not full, empty, 1=full, waiting to be read. |
| 2 | Overrun Error? 1=yes, 0=no. If a byte comes into the 6551 from the modem, and is not read before another one comes in and overwrites the first, an overrun error occurs. |
| 1 | Framing Error? 1=yes, 0=no. |
| 0 | Parity Error? 1=yes, 0=no. |
130 IF ( S AND 8 ) = 8 THEN R=PEEK(SW) : PRINT CHR$(R);
If the Receive Data Register is full, then get the byte. Location SW (Transmit and Receive Data Registers) is a dual-use register. Read it, and you get whatever is in the one-byte receive buffer; write to it, and you place a byte to be sent in the one-byte transmit buffer. So R=PEEK(SW) gets the byte. The rest of the line assumes the byte is an ASCII character, and just prints it out. Note that no true ASCII to PETSCII conversion is being done. If this were a more full-blown terminal, we would want the conversion done. This is just a quick and dirty example program.
140 IF (S AND 16)=16 THEN IF Z=1 THEN POKE SW,ASC(A$) : Z=0
If the Transmit Data Register is empty, and if there was a character read in back in line 100, then poke the numerical value of the character into the Transmit Data Register, and clear the flag for next time around.
150 GOTO 100
Do it all again 🙂
Run the program, and try a few commands:
ATZ will reset your modem. You should get the response “OK”. ATDTxxxxxxx where the x’s are a phone number will dial that number on a tone phone line. Type ATDP if you have a pulse line. You should hear a dial tone, and then hear your modem dial out.
To make a truly useful term program, assembly language has to be used. But there is nothing wrong with hacking around in BASIC, particularly if you have a SCPU, to experiment and learn in a more friendly environment. Also, interrupts really should be used, especially to read the incoming data. The SL will cause an interrupt (either NMI or IRQ, you choose with the switch on the cartridge) whenever a byte comes in, which you can then handle. The common thing to do is to add the incoming byte to a queue, and allow your main program to read from the queue at it’s leisure. A 256 byte buffer makes for an easy implementation. For transmitting, interrupts seem pretty cumbersome.
Have fun, and please, let me know what you’d like to see articles on. BBGRam? Demo coding tricks? Assembly tutorial? Making games? Disk drive programming? I’d like to hear from you – email me: macbeth@tbaytel.net