Program those DB-9 ports
By Patrick Bass, Antic ST Program Editor
Let's face it. Some programs work better with joysticks than with the keyboard or a mouse. People are comfortable with a joystick now. Some children have even grown up from infancy with a joystick in one hand. The Atari 520ST can access joysticks also, and this article will familiarize you with the methods needed to initialize and get readings from the joystick ports from C language. (Right at the start, we should tell you that we have not yet discovered how to do this from ST BASIC or LOGO.)
The Atari 520ST has two DB-9 joystick connectors located on the right side of the cabinet, towards the rear: Joy0 in front, and Joy1 in back. Standard Atari compatible switch-type joysticks plug into these ports. The front port, Joy0, can also support a mouse. Unlike the Atari 8-bit computers, the DB-9 ports on the 520ST will not support paddle controllers.
The two ports are each four bits of an eight-bit I/O port located directly on the 6301 Microprocessor that controls the keyboard. While these are normally input ports, they may also be set as output. HOW to set them as output is beyond the scope of this article. (Which gives you something to do, eh?)
The 6301 Keyboard Controller has the responsibility of keeping track of which key is pressed, where the mouse is, what state, (if any), the joysticks are in--and then communicating this information to the main 68000 processor. To know what to do, the keyboard is able to receive commands as well as report events. Sure enough, in the Atari Developers Kit documentation you can find at least two different ways of sending commands to the kekboard.
WHAT GOES ON?
In a nutshell, if we just wanted a joystick reading the process would go something like this: Send a joystick interrogation command to the keyboard, then wait in a loop until your joystick interrupt routine signals a "joystick packet" has been received from the keyboard. Now read the desired bytes out of the joystick packet. Sounds easy, right? Read on...
JOYSTICK ALA MODE
The joystick handler for the 520ST will operate in one of five modes: Disabled, Monitoring, Keycode, Event Reporting and interrogation. While this is more complex than an Atari 8-bit joystick, with complexity comes power. Let's closely examine each of the available modes.
DISABLED-- This is the mode TOS powers up in. Neither one of the ports are scanned or monitored for joystick information. To read information, the keyboard must be told which type of joystick scan to perform. To disable joystick reporting:
C Source code 68000 Assembly #define IKBD 4 move.w #$1a,-(sp) : move.w #$4,-(sp) : move.w #$3,-(sp) : trap #13 Bconout(IKBD,0 x la) addq.w #6,sp
MONITORING--Here we can instruct the keyboard to scan the joysticks every N hundredths of a second. Because this mode is incompatible with the defauit IKBD (Intelligent Keyboard) handler, users are encouraged to use another type of report, (keycode, event, or interrogation) or write their own IKBD handler. Monitoring mode is used mainly in game programming rather than general purpose programming.
KEYCODE--This mode allows the joysticks to return standard cursor key make/break control codes. The stick directions will emulate the cursor arrow keys and the joystick fire buttons will return $74/$F4 for Joy0 and $75/$F5 forJoy1.
EVENT REPORTING--This mode causes the joysticks' status to be reported every time a Joystick Event is detected. A Joystick Event is the closure or release of a joystick button or the physical movement of the joystick itself. This mode is supported by the default IKBD handler, but as the joysticks are initially disabled, the event reporting mode command ($14) must be sent to the keyboard first before any joystick information will be reported. Sample code to enable event reporting looks like:
C Source code 68000 assembly #define IKBD 4 move.w #$14,-(sp) : move.w #$4,(sp) : move.w #$3,-(sp) : trap #13 Bconout(IKBD,0x14) addq.w #6,sp
INTERROGATION-- This mode causes the joystick status to be reported every time an interrogation command ($16) is sent to the keyboard. This mode is also supported by the IKBD handler. But because the joysticks are initially disabled, you must first send an interrogation mode enable command ($15) to the keyboard. Sample code to enable interrogation mode is as follows:
C Source Code 68000 assembly #define IKBD 4 move.w ##$15,-(sp) : move.w #$4,-(sp) : move.w #$3,-(sp) : trap #13 Bconout(IKBD,0x15); addq.w #6,sp
To actually interrogate the joysticks, command #$16 is used, as in the following example:
C Source Code 68000 assembly #define IKBD 4 move.w #$16,-(sp) : move.w #b4,(sp) : move.w #$3,(sp) : trap #13 Bconout(IkBD.Oxlb); addq.w #6,sp
There is a row of nine addresses in memory called the Intelligent Keyboard Vector Base Table (IKBDVBASE). These addresses (numbered 0 to 8) are vectors which point to the different subroutines that will be performed whenever their associated keyboard interrupt is generated. Vector #6 is the pointer to a routine that handles the joystick interrupt.
To find vector #6 and activate the joysticks, we must first locate the beginning of the vector table. This is accomplished with BIOS #34, Kbdvbase(), which returns a LONG pointer to the start of the table. We now need to place the address of our own joystick interrupt routine in vector #6, so we take the LONG pointer returned from Kbdvbase(), add 24 to it--to account for six entries of four bytes each--and the result is where we place the LONG address of our own joystick interrupt handler.
To read the joystick, using Interrogate Mode, send an "interrogate joystick" ($16) command to the keyboard. Now sit in a loop for a short time while the keyboard computer reads the joystick ports and assembles the joystick packet.
This packet is nothing more than a collection of data the keyboard sends back about the state of the joystick. It comes in two forms--each two bytes long.
For Event Reporting Mode, the first byte in the packet is an identifier byte that describes which joystick the information comes from. Joy0 is identified by $FE and Joy1 is $FF. The second byte describes the bit pattern of the joystick press. Using the form: bxxxRLBF, bit 7 (b) denotes when the fire button is pressed. Bits 3, 2, 1 and 0 (R, L, B, F) are set whenever the joystick is pressed Right, Left, Back, or Front. Bits 4-6 are unused.
In Interrogation Mode, every time an interrogation command is sent, both joystick states are returned. The first byte in the packet is the bit-pattern from Joy0, and the second byte comes from Joy1, using the same bit-format as in Event Reporting Mode.
When the 520ST has assembled the joystick packet, it loads the address of the packet into a0 (and the stack) and then jumps through the (new) joystick interrupt vector. The joystick interrupt handler code should (at least) first save to the stack all registers used, then set a flag to show that a new joystick packet has been received.
Be sure and transfer the packet to your own buffer quickly, before a new packet is generated and overwrites the old packet. Then unstack and restore any registers used before returning through a RTS. Don't take more than 1 millisecond to do your interrupt work. And keep in mind this interrupt routine is performed within supervisor mode.
SAMPLE PROGRAM TAKE-APART
Examine Listing 1. This is a demonstration of joystick access using Interrogate Mode. It is written in Developers Alcyon C. At the top we have the typical #includes and #defines. CON stands for Consol--or video display-- IKBD for Intelligent Keyboard and CR and LF for Carriage Return and Line Feed.
Right under the integer declarations we have built two structs, or structures. These are arrays of information that can be manipulated easily from C. We build the first structure, called ikbdvbase, out of nine long words which each point to a different routine in the keyboard vector table. The next structure, savesys, is an image of the first, so we don't need to declare it. It will later be used to restore our original vectors.
In our Main() routine, we initialize() this application, do print out the values for stick(0) and stick(1) until [CONTROL] [C] is pressed, and then terminate() the application.
To initialize the application, we first make our standard v_opnvwk() call and set a flag which will be used later. Next, we find the starting address of the keyboard interrupt structure from Kbdvbase() and place it into a LONG variable called kbdvbase.
Using this value, the next nine lines will transfer the current vectors in the keyboard structure into our savesys structure we set earlier. Next, point just the joyvec vector (the joystick interrupt handler vector) to our routine with kbdvbase->joyvec=&joystick which means, "The kbdvbase structure entry joyvec gets replaced with the address of joystick()." And now we send an enable joystick scan instruction to the keyboard with Bconout( IKBD, 0x15 ).
To exit the program, we first stop joystick Bconout( IKBD,0 x la) command, then replace the used joystick interrupt vector, and re-initialize the mouse control for relative positioning. Finally, we close the work-station and exit the application.
STICK IT TO ME
The stick() routine sends the interrogation command to the keyboard computer, then waits while the keyboard reads the joysticks and assembles a packet. It waits inside the do statement which says, "Do nothing while flag is not set." When the joystick interrupt handler below receives a joystick packet, it will set flag, and stick() will continue. It resets the flag, picks up either packet or packet, depending on which stick was chosen, then returns the joystick state.
This is the routine that receives the joystick packet from the keyboard handler. It is performed during an interrupt, and under supervisor mode. (By the way, any attempt to perform I/O from here will result in disaster. Do your work as quickly as possible and leave.) We are passed a pointer to the packet in register a0 and also on the stack. This means we can access this value from C by declaring it as we enter the C routine. We do this at char buffer, which will assign the value on the stack (our address) to the array called buffer. This routine does nothing but transfer two bytes from buffer to packet, and sets flag to show reception of a packet.
HEX OUT NOW
The next routine, Pbyte( ), works with the following routine Pdigit( ) to print out values as hexadecinlal numbers. These numbers allow the bit-patterns of the joystick ports to be more easily deciphered.
That concludes this short discussion ofjoystick access on the Atari 520ST. To give you a further example, we included Listing 2, a bare-bones demonstration program featuring a bit of "Pong" and a taste of "breakout".
As written, neither of these games are particularly challenging--or bug-free. But they will run on all resolutions and should provide a practical demonstration of ST joystick programming. Take them apart, put them together, and create your own version of "Galaxian Swamp Beetles."
ST Resource would like to thank Richard Frick of Atari, and Dave Getreau, Senior Programmer at Atari, for his invaluable assistance and expertise on the subject of ST joystick control and the intelligent keyboard. --ST RESOURCE