Termulator For The 64
Gordon C. Lyman
"Termulator" is a speedy, machine language program which emulates a terminal program. It thus gives you an alternative if you find BASIC terminal programs too slow or if you cannot find suitable programs available commercially. You don't need to know machine language to type in and use this program. Termulator is limited to full duplex operation.
After buying a Commodore 64 computer and a VICmodem, I soon discovered that the terminal program supplied with the VICmodem would not run on the 64.I tried using a terminal program written in BASIC, but found it too slow for my purposes. Also, I could not find a terminal program offered for sale for the 64, so I wrote "Termulator" (terminal emulator), a machine language program which is quite simple in operation.
Basically, the program gets a character from the keyboard, sends the character via modem, receives a character from the modem, and finally displays it on screen. This simple logic limits the program's ability to full duplex operation; however, I have never required anything but full duplex operation. The program utilizes RAM in the range $0900-$8500 as a receive buffer, storing the text displayed on the screen into memory. Termulator consists of three basic sections: initialization, main loop, and cursor subroutine. Let's look at each one in some detail.
Termulator uses the Kernal routine "CLALL" ($FFE7) to close all files, just in case any have been left open. Next, the value $00 is stored in the RS-232 command register ($0294) and the value $06 is stored in the RS-232 control register ($293).
The next instructions set up a filename for the modem file. The location of the filename is loaded into the X and Y registers, and the length of the name is loaded into the accumulator. Now the important part: the first two bytes of the modem filename must be the RS-232 control and command registers. Then, by using the Kernal routine "SETNAM" ($FFBD), the RS-232 interface is instructed to operate according to the RS-232 control and command registers. In this case, the RS-232 interface will operate at 300 baud, with no parity checking, one stop bit, and an eight-bit word length. In order to change these, you must change the values that are loaded into these registers. For further explanation, see the Commodore 64 Programmer's Reference Guide.
A pointer in the zero page of memory is initialized to the start of the receive buffer. This buffer starts at $0900 in order to leave a cushion between the start of BASIC at $0800 and the buffer area. The pointer will be used by the main routine to store the text received into this buffer for future manipulations. The limit of memory pointer is reset in order to protect the file buffers which will be allocated when opening a file for the modem. The limit of memory pointer is also set low enough to protect a monitor or other program stored within the top 6656 bytes of RAM.
The program next sets up the logical first and secondary addresses and opens the modem file. This automatically allocates 512 bytes at the top of free RAM for input and output buffers. The accumulator is loaded with the file number, the X register is loaded with the device number, and the Y register is loaded with the secondary address, which would be a command to the modem. The value $FF loaded into the Y register means no command to the device. Then the "SETLFS" ($FFBA) and "OPEN" ($FFC0) Kernal routines are called.
The ASCII data from $C0F4 is displayed until a zero value is found. This includes the character codes to change to upper/lowercase and display white characters, as well as a title message.
The Main Loop ($C04A-$C0BF)
The Kernal routine "STOP" ($FFE1) is called, which will return a $00 in the accumulator if the stop key is pressed. If the stop key is pressed, all files are closed and the program stops; otherwise, the program branches to set the input device to device number 0 (the keyboard).
The Kernal routine "GETIN" ($FFE4) is used to return one byte from the keyboard buffer as an ASCII value in the accumulator. If the keyboard buffer was empty, a $00 is returned and the program will branch to the modem input routine. Otherwise, the ASCII value from the keyboard is stored in a zero page location ($6A) for later processing. The ASCII value from the keyboard is translated into standard ASCII by selecting the corresponding value from a list, 256 bytes long, starting at $C226. This is required because Commodore ASCII is not the same as standard ASCII. Also in this list of data are the ASCII values for the Control A through Control Z. When you wish to send a control character while using the program, type the appropriate letter key while holding down the Commodore key. Another list, starting at $C126, contains the Commodore ASCII for the reverse translation. The Kernal routine "CHROUT" ($FFD2) is used to send the byte, now in the accumulator, over the modem.
The Kernal routines "CHKIN" ($FFC6) and "CHRIN" ($FFE4) are used to input a byte from the modem. Then this byte, which is standard ASCII, is translated to Commodore ASCII and stored in zero page (at $6A).
If the value returned from the modem was null ($00), the program will branch back to the beginning of the main routine.
To erase the cursor before outputting to the screen, a space and cursor-left are displayed. Then the byte that was received from the modem is printed on the screen.
A check is made to see if the character received, now in the accumulator, is a delete. If it is, the receive buffer pointer is decremented and the program returns to the start of the main loop; if not, the receive buffer pointer is incremented. If the pointer has reached the limit of memory pointer, it is reset to $0900. The character is stored in the receive buffer, and the program returns to the start of the main loop.
The Cursor Subroutine ($C0C0-$C0F3)
The least significant byte of the Commodore 64's jiffy clock is used as a timer for the cursor. This byte is compared to the value $15, which is the length of time the cursor takes to flash on or off. By changing this value in location $C0C3, you can change the speed at which the cursor flashes. If the timer has not expired, then the RTS instruction at $C0C6 will return to the main routine.
If the timer has expired, it is reset and a flag stored at $6B is checked. This flag will be either $00 or $FF. If the flag is set to $FF, it will be cleared to $00 and a space which turns the cursor off will be displayed.
If the flag was clear, then the program branches to set the flag to $FF and displays a reversed space which turns the cursor on. After the cursor is turned either on or off, a cursor-left is displayed. This is done so that the next thing displayed will be in the right position. The program then returns to the main routine.
How To Use Termulator
Type in and RUN Program 1, which is a BASIC program that will load the machine language for Termulator into RAM. If any errors are detected, it will display the message ERROR IN BLOCK # x. You will need to check from $C300 to $C337 by hand. If no errors are found, the program is ready to run. Just type SYS 49152.
Once you've got a working version of Termulator, you can eliminate the trouble of having to run the BASIC loader program again by making a copy of the machine language on tape or disk. To do this, you'll need either a monitor program or a program like "Machine Language Saver" (COMPUTE!, June 1983). SAVE the contents of memory from 49152–49976 ($C000-$C338). When you reload the machine language, you start the program just as before, by typing SYS 49152.
Alternatively, you could use Program 2. This POKEs in a short routine which creates a tape copy of the Termulator machine language. Type in and RUN Program 2, insert a blank tape in the datassette, and type SYS 52736. You should see on your screen the prompt PRESS PLAY & RECORD ON TAPE, at which point you are ready to make the copy. You can reload Termulator from this tape by typing LOAD " ",1, 1.