- CHAPTER 5 -

# HARDWARE

#### Overview

This chapter will cover those aspects of Atari software programming that can only be accomplished by accessing hardware registers directly. In most cases, Atari has provided OS calls to manipulate the hardware. When an OS call exists to access hardware, it should always be used to ensure upward and backward compatibility. Keep in mind that access to hardware registers is limited to those applications operating in supervisor mode only (except where noted otherwise).

Besides those hardware registers discussed here, a complete list of I/O registers, system variables, and interrupt vectors are contained in Appendix B: Memory Map.

#### The 680x0 Processor

Atari computers use the Motorola MC68000 or MC68030. Third party devices have also been created to allow the use of a MC68010, MC68020, or MC68040 processor. The system cookie '_CPU' should be used to determine the currently installed processor. The following table lists the 680x0's interrupt priority assignments:

Level | Assignment
--- | ---
7 | NMI
6 | MK68901 MFP
5 | SCC
4 | VBLANK (Sync)
3 | VME Interrupter
2 | HBLANK (Sync)
1 | Unused

Interrupts may be disabled by setting the system interrupt mask (bits 8-10 of the SR register) to a value higher than the interrupts you wish to disable. Setting the mask to a value of 7 will effectively disable all interrupts (except the level 7 non-maskable interrupt).

##### The Data/Instruction Caches

The Atari TT030 and Falcon030 contain onboard data and instruction caches. These caches may be controlled by writing to the CACR register (in supervisor mode). The following table lists longword values that may be written to the CACR to enable or disable the caches:

Value to Write to CACR | Effect
--- | ---
0xA0A | Flush and disable both caches.
0x101 | Enable both caches.
0xA00 | Flush and disable the data cache.
0x100 | Enable the data cache.
0xA | Flush and disable the instruction cache.
0x1 | Enable the instruction cache.

#### The 68881/882 Floating Point Coprocessor

A MC6888x math coprocessor may be installed in a Mega ST, Mega STe, or a Falcon030. The TT030 has one installed in its standard configuration. The 6888x is interfaced to the 68000 in peripheral mode and to the 68030 in coprocessor mode. Thus, the TT030 and Falcon030 computers access the 6888x in coprocessor mode while the Mega ST and MegaSTe computers access the 6888x in peripheral mode.

##### Coprocessor Mode

When the 6888x is interfaced in coprocessor mode, using it is as simple as placing floating-point instructions in the standard instruction stream (use a coprocessor ID of 1). The 68030 will properly dispatch the instruction and respond to exceptions through the following vectors:

Vector Address | Assignment
--- | ---
0x0000001C | FTRAPcc Instruction
0x0000002C | F-Line Emulator
0x00000034 | Co-processor Protocol Violation
0x000000C0 | Branch or Set on Unordered Condition
0x000000C4 | Inexact Result
0x000000C8 | Floating-Point Divide by Zero
0x000000CC | Underflow
0x000000D0 | Operand Error
0x000000D4 | Overflow
0x000000D8 | Signaling NAN

##### Peripheral Mode

Utilizing an installed math coprocessor interfaced using peripheral mode requires the use of several hardware registers mapped to special coprocessor registers. Unlike most hardware registers, these do not have to be accessed in supervisor mode. Atari computers map the 6888x registers to the following locations:

Address | Length | Register | Description
--- | --- | --- | ---
0xFFFFFA40 | WORD | FPCIR | Status register
0xFFFFFA42 | WORD | FPCTL | Control Register
0xFFFFFA44 | WORD | FPSAV | Save Register
0xFFFFFA46 | WORD | FPREST | Restore Register
0xFFFFFA48 | WORD | FPOPR | Operation word register
0xFFFFFA4A | WORD | FPCMD | Command register
0xFFFFFA4C | WORD | FPRES | Reserved
0xFFFFFA4E | WORD | FPCCR | Condition Code Register
0xFFFFFA50 | LONG | FPOP | Operand Register

To execute a floating point instruction, use the following protocol for communicating data with the 6888x:

1. Wait for the chip to be idle.

2. Write a valid 6888x command to FPCMD.

3. If necessary for the command, write an operand to FPOP.

4. Wait for the status port to indicate the command is complete.

5. Read any return data from FPOP.

Step one is achieved by waiting for a value of 0x0802 to appear in the status register (after ANDing with 0xBFFF) as follows:

    while( ( FPCIR & 0xBFFF) != 0x0802 ) ;

Steps two and three involve writing the command word to FPCMD and any necessary operand data to FPOP. A primitive response code will be generated (and should be read) between each write to either FPCMD or FPOP. For a listing of primitive response codes returned by the 68881, consult the MC68881/68882 Floating-Point Coprocessor User's Manual (2nd edition), Motorola publication MC68881UM/AD rev. 2, ISBN 0-13-567-009-8.

After the operation is complete (step 4), data may be read from the 68881 in FPOP (step 5).

When sending or receiving data in FPOP, the following chart details the transfer ordering and alignment:

The following code demonstrates transferring two single precision floating-point numbers to the 68881, multiplying them, and returning the result.

    /* Number of iterations before an error is triggered */
    #define FPCOUNT		0x80

    #define FPCIR			((WORD *)(0xFFFFFA40L))
    #define FPCMD			((WORD *)(0xFFFFFA4AL))
    #define FPOP			((float *)(0xFFFFFA50L))

    WORD fpcount, dum;

    /* fperr() is user-defined */

    #define FPwait() { 	fpcount = FPCOUNT; \
    					while((*FPCIR & 0xBFFF) != 0x0802) \
    						if(!(--fpcount)) fperr();	 }

    #define FPsglset(r,v) { FPwait(); \
    					  *FPCMD = (0x5400 | ((r) << 7)); \
    					  while((*FPCIR & 0xFFF0) != 0x8C00) \
    						if(!(--fpcount)) fperr();		\
    					  *FPOP = (v); }

    #define FPsglmul(r1,r2) { 	FPwait();	\
    						*FPCMD = (0x0027 | ((r2) << 10) | ((r1) << 7));		\
    						dum = *FPCIR + 1;	}

    /* dum = FPCIR +1; forces the status register to be read
       (we assume the data's good) */

    #define FPsglget(r,var) {	FPwait();	\
    						*FPCMD = (0x6400 | ((r) << 7));		\
    						while(*FPCIR != 0xb104)		\
    							if(!(--fpcount)) fperr();		\
    						var = *FPOP;		}

    /*
     * void sglmul( float *f1, float *f2 );
     *
     * Multiplies f1 by f2. Returns result in f1.
     *
     */

    void
    sglmul( float &f1, float &f2 )
    {
    	FPsglset( 0, *f1 );
    	FPsglset( 1, *f2 );
    	FPsglmul( 0, 1 );
    	FPsglget( 0, *f1 );
    }

#### Cartridges

All Atari computers support an external 128K ROM cartridge port. Cartridges may be created to support applications or diagnostic tools. The 128K of address space allocated to cartridges appears from address 0xFA0000 to 0xFBFFFF. Newer Atari computers support larger cartridges (this is because the address space would no longer overlap the OS). All program code must be compiled to be relative of this base address.

The LONG appearing at 0xFA0000 determines the type of cartridge installed as follows:

Cartridge | LONG Value
--- | ---
Application | 0xABCDEF42
Diagnostic | 0xFA52255F

##### Diagnostic Cartridges

Diagnostic cartridges are executed almost immediately after a system reset. The OS uses a 680x0 JMP instruction to begin execution at address 0xFA0004 after having set the Interrupt Priority Level (IPL) to 7, entering supervisor mode, and executing a RESET instruction to reset external hardware devices.

Upon execution, register A6 will contain a return address which should be JMP'd to if you wish to continue system initialization at any point. The stack pointers will contain garbage. In addition, keep in mind that no hardware has been initialized, particularly the memory controller. All system memory sizing and initialization must be performed by the diagnostic cartridge.

##### Application Cartridges

Application cartridges should contain one or more application headers beginning at location 0xFA0004 as follows (one cartridge may contain one or many applications):

Name | Offset | Meaning
--- | --- | ---
CA_NEXT | 0x00 | Pointer to the next application header (or NULL if there are no more).
CA_INIT | 0x04 | Pointer to the application's initialization code. The high eight bits of this pointer have a special meaning as follows: Bit Set Meaning 0 Execute prior to display memory and interrupt vector initialization. 1 Execute just before GEMDOS is initialized. 2 (unused) 3 Execute prior to boot disk. 4 (unused) 5 Application is a Desk Accessory. 6 Application is not a GEM application. 7 Application needs parameters.
CA_RUN | 0x08 | Pointer to application's main entry point.
CA_TIME | 0x0C | Standard GEMDOS time stamp.
CA_DATE | 0x0E | Standard GEMDOS date stamp.
CA_SIZE | 0x10 | Size of application in bytes.
CA_NAME | 0x14 | NULL terminated ASCII filename in standard GEMDOS 8+3 format.

When application cartridges are present, GEMDOS will allow a special 'c' (lowercase) drive to be accessed. Executable files appear on this drive as they would on any standard disk. This 'drive' may also be installed on the desktop.

#### Game Controllers

The Atari 1040STe and Falcon030 support new enhanced joystick controls as well as older style CX-40 controls. For the usage and polling of the older style controls, refer to the following section which discusses the IKBD controller. This section will focus specifically on the newer style of controllers.

##### Joysticks

Enhanced joysticks are read by a two-step process. The WORD at address 0xFF9202 is written to using a mask which determines which values may subsequently be read from the WORDs at address 0xFF9200 and 0xFF9202. Valid mask values and the keys that may be read follow:

Read Controller 0 at 0xFF9200
Write Mask | Bit 0 Clear | Bit 1 Clear
0xFFFE | Pause | Fire 0
0xFFFD | - | Fire 1
0xFFFB | - | Fire 2
0xFFF7 | - | Option

Read Controller 1 at 0xFF9200
Write Mask | Bit 2 Clear | Bit 3 Clear
0xFFEF | Pause | Fire 0
0xFFDF | - | Fire 1
0xFFBF | - | Fire 2
0xFF7F | - | Option

Read Controller 0 at 0xFF9202
Write Mask | Bit 8 Clear | Bit 9 Clear | Bit 10 Clear | Bit 11 Clear
0xFFFE | Up | Down | Left | Right
0xFFFD | Key * | Key 7 | Key 4 | Key 1
0xFFFB | Key 0 | Key 8 | Key 5 | Key 2
0xFFF7 | Key # | Key 9 | Key 6 | Key 3

Read Controller 1 at 0xFF9202
Mask | Bit 12 Clear | Bit 13 Clear | Bit 14 Clear | Bit 15 Clear
0xFFEF | Up | Down | Left | Right
0xFFDF | Key * | Key 7 | Key 4 | Key 1
0xFFBF | Key 0 | Key 8 | Key 5 | Key 2
0xFF7F | Key # | Key 9 | Key 6 | Key 3

To read the joystick, write a mask value corresponding to the row of keys/positions you wish to interrogate to 0xFF9202. Next, read back a WORD from either 0xFF9200 or 0xFF9202. As indicated in the table, cleared bits mean that a key is being pressed or a joystick is moved in that direction.

##### Paddles

Two paddles may be plugged into each joystick port. Each paddle returns an 8-bit value indicating its position ( 0 = full counter-clockwise, 255 = full clockwise) at the addresses shown below. Unlike joysticks, paddle positions are returned automatically with no need to write to an address prior to a read. Paddle fire buttons, however, are mapped and read in the same manner as the joysticks. See the discussion of joysticks above for an explanation.

Byte Address | Paddle
--- | ---
0xFF9211 | X Paddle 0
0xFF9213 | Y Paddle 0
0xFF9215 | X Paddle 1
0xFF9217 | Y Paddle 1

##### Light Gun/Pen

Joystick port 0 supports a light gun or pen. The position that the gun is pointing to is returned in the WORD registers at 0xFF9220 (X position) and 0xFF9222 (Y position). Only the lower 10 bits are significant giving a range of values from 0-1023.

#### The IKBD Controller

The Atari 16/32 bit computer line uses the Intelligent Keyboard Controller (IKBD) for keyboard, joystick (old-style CX-40), mouse, and clock communication. The 6850 ACIA serial communications chip is used to transfer data packets from the IKBD interface to the host computer.

The TOS calls Bconout( 4, ??? ), Ikbdws(), and Initmous() handle communication to the controller. Return messages from the controller must be processed by placing a specialized handler in the vector table returned by the XBIOS call Kbdvbase(). Kbdvbase() returns the pointer to a vector table as follows:

    typedef struct
    {
    void (*midivec)( UBYTE data );		/* Passed in d0 */
    	void (*vkbderr)( UBYTE data );		/* Passed in d0 */
    	void (*vmiderr)( UBYTE data );		/* Passed in d0 */
    	void (*statvec)( char *packet );		/* Passed in a0 */
    	void (*mousevec)( char *packet );		/* Passed in a0 */
    	void (*clockvec)( char *packet );		/* Passed in a0 */
    	void (*joyvec)( char *packet );		/* Passed in a0 */
    	void (*midisys)( VOID );
    	void (*ikbdsys)( VOID );
    	char ikbdstate;
    } KBDVECS;

When an IKBD message is pending, the interrupt handler for the ACIAs calls either the midisys handler or the ikbdsys handler to retrieve the data and handle any errors. The default action for the ikbdsys handler is to decide whether the packet contains error, status, joystick, clock, or mouse information and to route it appropriately to vkbderr, statvec, joyvec, clockvec, or mousevec. Keyboard packets are handled internally by ikbdsys.

Your handler should be patched into the appropriate vector and, if appropriate, expect the packet buffer to be pointed to by register A0. Unless your handler is designed to completely replace the functions of the default handler you should jump through the original vector pointer upon exit, otherwise simply use the 680x0 RTS instruction.

Each byte received through the keyboard ACIA falls into one of the following categories as follows:

Category | Value(s) | Meaning
--- | --- | ---
Keyboard Make Code | 0x00-0x7F | One of these values is generated each time a key is depressed.This value may be used with Keytbl() to generate an ASCII code for the scan code.
Keyboard Break Code | 0x80-0xFF | This code is generated when a key previously depressed has been released. It represents the make code logically OR'ed with 0x80.
Status Packet Header | 0xF6 | This codes indicate the beginning of a multiple byte status packet.
Absolute Mouse Position | 0xF7 | See Below
Relative Mouse Position | 0xF8-0xFB | See Below
Time-of-Day | 0xFC | See Below
Joystick Report | 0xFD | See Below
Joystick 0 Event | 0xFE | See Below
Joystick 1 Event | 0xFF | See Below
Status Packet Data | Any | When the ikbdstate variable (found in the KBDVECS structure) is non-zero, it represents the number of remaining bytes to retrieve that are part of a status packet and should thus not be treated as any of the above codes.

##### The Keyboard

Keyboard keys generate both a 'make' and 'break' code for each complete press and release respectively. The 'make' code is equivalent to the high byte of the IKBD scan code. 'make' codes are not related in any way to ASCII codes. They represent the physical position of the key in the keyboard matrix and may vary in keyboards designed for other countries. The XBIOS function Keytbl() provides lookup values which make internationalization possible. The key 'break' code is the 'make' code logically ORed with 0x80.

It should be noted that 'key repeats' are not generated by the ACIA but by a coordination of the ikbdsys and system timer handlers.

##### The Mouse

The mouse may be programmed to return position reports in either absolute, relative, or keycode mode (it is by default programmed to return relative position reports).

In relative reporting mode, the IKBD generates a mouse packet each time a mouse button is pressed or released, and every time the mouse is moved over a preset threshold distance (which is configurable). A relative mouse report packet is headed by a byte value between 0xF8 and 0xFB followed by the X and Y movement of the mouse as signed bytes. If the movement is greater than can be represented as signed bytes (-128 to 127), multiple packets are sent.

The header byte determines the state of the mouse buttons as follows:

Header | Mouse Button State
--- | ---
0xF8 | No buttons depressed.
0xF9 | Left button depressed.
0xFA | Right button depressed.
0xFB | Both buttons depressed.

In absolute reporting mode, the IKBD only generates a mouse packet when interrogated. Mouse packets in absolute mode are headed by a 0xF7 byte followed by the MSB and LSB of the X value and the MSB and LSB of the Y value respectively. The minimum and maximum X and Y values are user-definable.

Keycode reporting mode generates keyboard 'make' and 'break' codes for mouse movements rather than sending standard mouse packets. Mouse movement is translated into the arrow keys and the codes 0x74 and 0x75 represent the left and right mouse button respectively. 'break' codes are sent immediately after the corresponding 'make' code is delivered.

##### The Joystick

The basic CX-40 style joystick controls are still present on every Atari computer. Atari recommends that these ports should not be supported when STe/Falcon030 enhanced joysticks are present unless the option for four-player play is desired. While no direct TOS support is available for reading these ports, it is possible using the IKBD controller in one of several joystick reporting modes.

Joystick event reporting mode (the default) sends a joystick packet each time the status of one of the joysticks changes. The joystick packet header is 0xFE if the state of joystick 0 has changed or 0xFF if the status of joystick 1 has changed. This header byte is followed by a BYTE containing the new state of the joystick as follows:

The four bits corresponding to joystick position can be interpreted as follows:

Joysticks may be interrogated at any time by sending an interrogate command (as described later in this chapter). The packet response to this command is 0xFD followed by the BYTE report of joystick 0 and 1 (as shown above).

The joysticks may be placed into joystick monitoring or fire button monitoring mode. In these modes, all other IKBD communication is stopped and all processor time is devoted to the processing of packets. Joystick monitoring mode cause the IKBD to send a continuous stream of two-byte packets as follows: The first byte contains the status of joystick buttons 0 and 1 in bits 1 and 0 respectively. The second byte contains the position state of joystick 0 in the high nibble and joystick 1 in the lower nibble (the position state can be interpreted as shown in the diagram above).

Fire button monitoring mode constantly scans joystick button 1 and returns the results in BYTEs packed with 8 reports each (one per bit). These modes may be paused or halted using the appropriate commands.

Joystick keycode mode is similar to mouse keycode mode. This mode translates all joystick position information into arrow keys. A 'make' code of 0x74 is generated when joystick button 0 is depressed and a 'make' code of 0x75 is generated when joystick button 1 is depressed. The rate at which the IKBD controller generates these joystick events can be controlled using commands discussed in the following section.

##### Time-of-Day

The IKBD controller maintains a separate time-of day clock that is kept synchronized with GEMDOS time by OS calls. A time-of-day packet may be requested using the method shown below under IKBD commands.

The response packet from the IKBD is seven bytes in length identified by its header byte of 0xFC and followed by six UBYTES containing the year (last two digits), month, day, hours (0-24), minutes, and seconds in BCD format (ex: a month byte in December would be 0x12).

##### IKBD Commands

Commands may be sent to the IKBD using any of the TOS function calls described above. Some commands may generate packets while other commands change the operating state of the IKBD controller. Unrecognized command codes are treated as NOPs. The following lists valid IKBD command codes:

Command BYTE | Result
--- | ---
0x07 | Set mouse button action. This command BYTE should be followed by a BYTE which describes how the mouse buttons should be treated as follows: BYTE Meaning 0x00 Default mode. 0x01 Mouse button press triggers an absolute position report. 0x02 Mouse button release triggers an absolute position report. 0x03 Mouse button press and release triggers absolute position reports. 0x04 Mouse buttons report key presses.
0x08 | Enable relative mouse position reporting (default).
0x09 | Enable absolute mouse position reporting. This command is followed by the MSB and LSB of the X and Y coordinate maximum values for the mouse.
0x0A | Enable mouse keycode mode. This command is followed by two BYTEs indicating the maximum number of mouse 'ticks' required to generate a keycode for the X and Y axis respectively.
0x0B | Set mouse threshold. This command is followed by two BYTEs which determine the number of mouse 'ticks' required to generate a mouse position report in relative positioning mode.
0x0C | Set mouse scale. This command is followed by two BYTEs which determine the number of mouse 'ticks' for each single coordinate on the X and Y axis respectively.
0x0D | Interrogate mouse position. This command generates an absolute mouse position report.
0x0E | Load mouse position. This command sets the mouse position based on the current coordinate system in absolute reporting mode. The command is followed by a filler BYTE of 0x00 and the MSB and LSB of the new X and Y axis for the mouse.
0x0F | Set Y=0 to the bottom. This command changes the origin of the mouse coordinate system to the upper left of the screen.
0x10 | Set Y=0 to the top. This command changes the origin of the mouse coordinate system to the lower left of the screen.
0x11 | Resume sending data. This command (or for that matter any command) will cause the IKBD to resume sending packet data to the host.
0x12 | Disable all mouse packet reporting. Any valid mouse command resets this state. If the mouse buttons have been programmed to act like keyboard keys, this command will have no effect on them.
0x13 | Pause output. All output from the IKBD controller is halted until a 'Resume' or other command is received.
0x14 | Set joystick event reporting mode. This command causes a joystick report to be generated whenever the state of either joystick changes.
0x15 | Set joystick interrogation mode. This command causes the IKBD to generate joystick packets only when requested by the host.
0x16 | Joystick interrogation. This command causes a joystick packet indicating the status of both joysticks to be generated.
0x17 | Enables joystick monitoring mode. Besides serial communication and the maintenance of the time-of-day clock, this command causes only special joystick reports to be generated. The command BYTE should be followed by a BYTE indicating how often the joystick should be polled in increments of 1/100ths of a second.
0x18 | Enables fire button monitoring mode. As above, this mode limits the IKBD to serial communication, updating the time-of-day clock, and the reporting of the state of joystick button 1.
0x19 | Set joystick keycode mode. This command is followed by six BYTEs as follows: BYTE Meaning 1 The length of time (in tenths of a second) before the horizontal breakpoint is reached. 2 Same as above for the vertical plane. 3 The length of time (in tenths of a second) between key repeats before the velocity breakpoint is reached. 4 Same as above for the vertical plane. 5 The length of time (in tenths of a second) between key repeats after the velocity breakpoint is reached. 6 Same as above for the vertical plane.
0x1A | Disable joystick event reporting.
0x1B | Set the time of day clock. This command is followed by six BYTEs used to set the IKBD clock. These BYTEs are in binary-coded decimal (BCD) format. Each BYTE contains two digits (0-9), one in each nibble. The format for these BYTEs is as follows: BYTE Meaning 1 Year (last two digits) 2 Month 3 Date 4 Hours (0-23) 5 Minutes (0-59) 6 Seconds (0-59)
0x1C | Interrogate the time-of-day clock. This command returns a packet headed by the value 0xFC followed by six BYTEs as indicated above.
0x20 | Load BYTEs into the IKBD memory. This command is followed by at least three BYTEs containing the MSB and LSB of the address into which to load the data, the number of BYTEs to load (0-127), and the data itself.
0x21 | Read BYTEs from the IKBD controller. This command is followed by two BYTEs containing the MSB and LSB of the address to read from. This returns a packet headed by the BYTE values 0xF6 and 0x20 followed by the memory data.
0x22 | Execute a subroutine on the IKBD controller. This command BYTE is followed by two BYTEs containing the MSB and LSB of the memory location of the subroutine to execute.
0x80 | Reset the IKBD controller. This command is actually a two-BYTE command. The BYTE 0x80 must be followed by a BYTE of 0x01 or the command will be ignored.
0x87 | Return a status message containing the current mouse action state. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 0x07 3 Current mouse action state (see command 0x07) 4-8 0
0x88 | Return a status message containing the current mouse mode. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 Current mode as follows: 0x08 = Relative mode 0x09 = Absolute mode 0x0A = Keycode mode 3 Absolute mode: MSB of maximum X position (units to current scale). Keycode mode: Horizontal distance threshold that must be passed prior to sending a keycode. Relative mode: 0 4 Absolute mode: LSB of maximum X position. Keycode mode: Vertical distance threshold that must be passed prior to sending a keycode. Relative mode: 0 5 Absolute mode: MSB of maximum Y position (units to current scale). Keycode mode: 0 Relative mode: 0 6 Absolute mode: LSB of maximum Y position. Keycode mode: 0 Relative mode: 0 7-8 0
0X89 | Same as 0x88.
0X8A | Same as 0x88.
0x8B | Return a status message containing the current mouse threshold state. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 0x0B 3 Number of horizontal mouse 'ticks' that must be traveled prior to sending a mouse packet. 4 Number of vertical mouse 'ticks' that must be traveled prior to sending a mouse packet. 5-8 0
0x8C | Return a status message containing the current mouse scaling factor. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 0x0C 3 Horizontal mouse 'ticks' between a change in mouse position on the X axis. 4 Vertical mouse 'ticks' between a change in mouse position on the Y axis. 5-8 0
0x8F | Return a status message containing the current origin point of the Y axis used for mouse position reporting. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 0x0F = Bottom is (Y=0) 0x10 = Top is (Y=0) 3-8 0
0x90 | Same as 0x8F.
0x92 | Return a status message containing the current state of mouse reporting. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 0x00 = Mouse reporting enabled. 0x12 = Mouse reporting disabled. 3-8 0
0x94 | Return a status message containing the current joystick mode. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 Current mode as follows: 0x14 = Event reporting mode 0x15 = Interrogation mode 0x19 = Keycode mode 3 Keycode mode: This value represents the amount of time (in tenths of a second) that keycodes are returned to the host for horizontal position events at the initial velocity level (after this time expires, the secondary velocity level is used). Event recording mode: 0 Interrogation mode: 0 4 Keycode mode: Same as BYTE 3 for vertical events. Event recording mode: 0 Interrogation mode: 0 5 Keycode mode: This value represents the initial horizontal velocity level (in tenths of a second). This is the initial rate at which keycodes are generated. Event recording mode: 0 Interrogation mode: 0 6 Keycode mode: Same as byte 5 for vertical events. Event recording mode: 0 Interrogation mode: 0 7 Keycode mode: This value represents the secondary horizontal velocity level (in tenths of a second). This is the rate used after the amount of time specified in bytes 3-4 expires. Event recording mode: 0 Interrogation mode: 0 8 Keycode mode: Same as byte 7 for vertical events. Event recording mode: 0 Interrogation mode: 0
0x95 | Same as 0x94.
0x99 | Same as 0x94.
0x9A | Return a status message containing the current status of the joystick. After receiving this command the IKBD will respond by sending a status packet (which may be intercepted at statvec) as follows: BYTE Meaning 1 0xF6 2 0x00 = Joystick enabled 0x1A = Joystick disabled 3-8 0

#### STe/TT030 DMA Sound

The Atari STe, Mega STe, TT030, and Falcon030 are all equipped with the ability to playback stereo digital audio. Only the Falcon030, however, has supporting XBIOS calls which eliminate the need for the programmer to directly access the sound system hardware. Although the Falcon030 has a more sophisticated sound system than the earlier Atari machines, the hardware registers have been kept compatible so older applications should function as expected. Programmers designing Falcon030 applications which use digital audio should use the appropriate XBIOS calls.

The STe, MegaSTe, and TT030 support 8-bit monophonic or stereophonic sound samples. Samples should be signed ( -128 to 127) with alternating left and right channels (for stereo) beginning with the left channel. Samples may be played at 50 kHz, 25 kHz, 12.5 kHz, or 6.25 kHz (6.25 kHz is not supported on the Falcon030).

##### DMA Sound Registers

Several hardware registers control DMA sound output as follows:

Address | Bit Layout | Meaning
--- | --- | ---
0xFF8900 |
    ---- ---- ---- --cc
| Sound DMA Control
0xFF8902 |
    ---- ---- 00xx xxxx
| Frame Base Address High (bits 21-16)
0xFF8904 |
    ---- ---- xxxx xxxx
| Frame Base Address Middle (bits 15-8)
0xFF8906 |
    ---- ---- xxxx xxx0
| Frame Base Address Low (bits 7-1)
0xFF8908 |
    ---- ---- 00xx xxxx
| Frame Address Counter (bits 21-16)
0xFF890A |
    ---- ---- xxxx xxxx
| Frame Address Counter (bits 15-8)
0xFF890C |
    ---- ---- xxxx xxx0
| Frame Address Counter (bits 7-1)
0xFF890E |
    ---- ---- 00xx xxxx
| Frame End Address High (bits 21-16)
0xFF8910 |
    ---- ---- xxxx xxxx
| Frame End Address Middle (bits 15-8)
0xFF8912 |
    ---- ---- xxxx xxx0
| Frame End Address Low (bits 7-1)
0xFF8920 |
    0000 0000 m000 00rr
| Sound Mode Control

Addresses placed in the three groups of address pointer registers must begin on an even address. In addition, only sounds within the first 4 megabytes of memory may be accessed (this limitation has been lifted on the Falcon030). Sounds may not be played from alternate RAM.

##### Playing a Sound

To begin sound playback, place the start address of the sound in the Frame Base Address registers. Place the address of the end of the sound in the Frame End Address registers. The address of the end of the sound should actually be the first byte in memory past the last byte of the sample.

Set the Sound Mode Control register to the proper value. Bit 7, notated as 'm' should be set to 1 for a monophonic sample or 0 for a stereophonic sample. Bits 0 and 1, notated as 'r', control the sample playback rate as follows:

'r' | Playback Rate
--- | ---
00 | 6258 Hz
01 | 12517 Hz
10 | 25033 Hz
11 | 50066 Hz

To begin the sample playback, set bits 0 and 1 of the Sound DMA Control register, notated as 'c', as follows:

'c' | Sound Control
--- | ---
00 | Sound Disabled (this will stop any sound currently being played)
01 | Sound Enabled (play once)
11 | Sound Enabled (repeat until stopped)

Sound playback may be prematurely halted by writing a 0 to address 0x00FF8900.

##### Sound Interrupts using MFP Timer A

Discontinuous sample frames may be linked together using the MFP Timer A interrupt. When a sound is played using repeat mode an interrupt is generated at the end of every frame. By configuring Timer A to 'event count' mode you can ensure the seamless linkage and variable repeating of frames.

For example, suppose you have three sample frames, A, B, and C, in memory and you want to play A five times, B five times, and C only once. Use the following steps to properly configure Timer A and achieve the desired result:

Use Xbtimer() to set Timer A to event count mode with a data value of 4 (the first data value should be one less than actually desired since the sound will play once before the interrupt occurs).

Configure the sound registers as desired and start sound playback in repeat mode.

When the interrupt fires, place the address of frame B in the sound playback registers (these values aren't actually used until the current frame finishes).

Reset Timer A's data register to 5 and exit your interrupt handler.

When the second interrupt fires, place the address of frame C in the sound playback registers.

Reset Timer A's data register to 1 and exit your interrupt handler.

When the final interrupt is triggered, write a 0x01 to the sound control register to cause sound playback to end at the end of the current frame.

##### Sound Interrupts using GPIP 7

Another method of generating interrupts at the end of sound frames is by using the MFP's General Purpose Interrupt Port (GPIP) 7. This interrupt does not support an event count mode so it will generate an interrupt at the end of every frame. In addition, the interrupt must be configured differently depending on the type on monitor connected to the system (this is because GPIP 7 serves double-duty as the monochrome detect signal).

To program GPIP 7 for interrupts, disable all DMA sound by placing a 0x00 in the sound control register. Next, check bit 7 of the GPIP port at location 0xFFFA01. If a monochrome monitor is connected the bit will be 0. The bit will be 1 if a color monitor is connected.

Bit 7 of the MFP's active edge register (at 0xFFFA03) should be set to the opposite of the GPIP port's bit 7. This will cause an interrupt to trigger at the end of every frame. Use Mfpint() to set the location of your interrupt handler and Jenabint() to enable interrupts. From this point, interrupts will be generated at the end of every frame playing in 'play once' mode or repeat mode until the interrupt is disabled.

#### The MICROWIRE Interface

The STe and TT030 computers use the MICROWIRE interface to control volume, mixing of the PSG and DMA output, and tone control. The original ST is limited to amplitude control through the use of the appropriate PSG register. The Falcon030 supports new XBIOS calls which allow volume and mixing control.

The MICROWIRE interface is a write-only device accessed using two hardware registers 0xFFFF8924 (mask) and 0xFFFF8922 (data). To write a command to the MICROWIRE you must first place the value 0x07FF into the mask register and then write the appropriate command to the data register. The format for the data WORD is shown below:

Bits labeled 'x' will be ignored. Bits 9 and 10 should always be %10 to correctly specify the device address which is a constant. Bits labeled 'c' specify the command and bits labeled 'd' contain the appropriate data for the command. The following table explains the valid MICROWIRE commands:

Command | 'ccc' | 'dddddd'
--- | --- | ---
Set Master Volume | 011 | Example Value Result %000000 -80dB Attenuation %010100 -40dB Attenuation %101000 0dB Attenuation (Maximum)
Set Left Channel Volume | 101 | Example Value Result %000000 -40dB Attenuation %001010 -20dB Attenuation %010100 0dB Attenuation (Maximum)
Set Right Channel Volume | 100 | Example Value Result %000000 -40dB Attenuation %001010 -20dB Attenuation %010100 0dB Attenuation (Maximum)
Set Treble | 010 | Example Value Result %000000 -12dB Attenuation %000110 0dB Attenuation %001100 +12dB Attenuation (Maximum)
Set Bass | 001 | Example Value Result %000000 -12dB Attenuation %000110 0dB Attenuation %001100 +12dB Attenuation (Maximum)
Set PSG/DMA Mix | 000 | Example Value Result %000000 -12dB Attenuation %000001 Mix PSG sound output. %000010 Don't Mix PSG sound output.

When configuring multiple settings at once, you should program a delay between writes since the MICROWIRE takes at least 16sec to completely read the data register. During a read the MICROWIRE rotates the mask register one bit at a time. You will know a read operation has completed when the mask register returns to 0x07FF. The following assembly segment illustrates this by setting the left and right channel volumes to their maximum values:

    MWMASK			EQU		$FFFF8924
    MWDATA			EQU		$FFFF8922

    MASKVAL			EQU		$7FF
    HIGHLVOL		EQU		$554
    HIGHRVOL		EQU		$514

    			.text

    maxvol:
    			move.w	MASKVAL,MWMASK		; First write the mask and data values
    			move.w	#HIGHLVOL,MWDATA
    mwwrite:
    			cmp.w	MASKVAL,MWMASK
    			bne.s	mwwrite				; loop until MWMASK reaches $7FF again
    			move.w	#HIGHRVOL,MWDATA		; ok, safe to write second value
    			rts

    			.end

#### Video Hardware

##### Video Resolutions

Atari computers support a wide range of video resolutions as shown in the following tables:

Computer System | Modes (width height colors) | Possible Colors
--- | --- | ---
ST, Mega ST | 320x200x16 640x200x4 640x400x2 | 512
STe, Mega STe | 320x200x16 640x200x4 640x400x2 | 4096
STacy | 640x400x2 | N/A
TT030 | 320x200x256 640x200x4 640x400x2 320x480x256 640x480x16 | 4096
Falcon030 | See below. | 262,144

##### Falcon030 Video Modes

The Falcon030 is equipped with a much more flexible video controller than earlier Atari computers. The display area may be output on a standard television, an Atari color or monochrome monitor, or a VGA monitor. Overscan is supported with all monitor configurations with the exception of VGA. Also, hardware support for NTSC and PAL monitors is software configurable.

The Falcon030 supports graphic modes of 40 or 80 columns (320 or 640 pixels across) containing 1, 2, 4, 8, or 16 bits per pixel resulting in 2, 4, 16, 256, or 262,144 colors respectively. All modes except the 16 bit per pixel mode supply the video shifter with palette indexes. The 16 bit per pixel mode is a 'true-color' mode where each 16 bit value determines the color rather than being an index into a palette. Each 16 bit WORD value is arranged as follows:

The 'R', 'G', and 'B', represent the red, green, and blue components of the color. Because red and blue are each allocated five bits, they can represent a color range of 0-31. The green component is allocated six bits so it can represent a color range of 0-63.

The Falcon030 also supports an overlay mode (see VsetMask()) where certain colors can be defined as transparent to a connected Genlock (or similar) device. In this mode, the least signifigant green bit (Bit #5) is treated as the transparent flag bit and the resolution of the green color component is slightly reduced. If the transparent flag bit of a pixel is set, that pixel will display video from the Falcon030's video shifter, otherwise the external video source will be responsible for its display.

Another feature of the Falcon030's video shifter is an optional interlace/double-line mode. When operating on a VGA monitor, this mode doubles the pixel height effectively reducing the vertical screen resolution by half. On any other video display, this mode engages interlacing which increases the video resolution.

The operating system calls VsetMode() or VsetScreen() can be used to manipulate the operating mode of the Falcon030's video shifter. These calls do not, however, do any checking to ensure the selected video mode is actually attainable on the connected monitor or that the mode is legal. In particular, you should not attempt to set the video shifter to either 40 column mode with only one bit per pixel or 80 column VGA mode with 16 bits per pixel.

##### Video Memory

Most of the available video modes are palette-based. The number of bits required per pixel depends on the number of palette entries as shown in the table below. The Falcon030 also offers a true color video mode which requires 16 bits per pixel.

Palette Entries | Bits per Pixel
--- | ---
2 | 1
4 | 2
16 | 4
256 | 8

Directly accessing video memory is normally not recommended because it may create compatibility problems with future machines and wreak havoc with other system applications. The VDI provides a rich set of function calls which should be used when outputting to the screen. The function call vr_trnfm(), for instance, can be useful in transforming video images into a pattern compatible with the current video shifter. Certain software, however, does need exclusive access to video memory.

With the exception of the 16-bit true color mode of the Falcon030, all video images are stored in memory in WORD interleaved format. The video shifter grabs one at a time from each plane present as shown in the following diagram which represents a 16-color (four plane) screen layout:

The Falcon030's 16-bit true color mode is pixel-packed so that WORD #0 in memory is the complete color WORD for the pixel at ( 0, 0 ), WORD #1 is the complete color WORD for the pixel at ( 1, 0 ), etc.

##### Fine Scrolling

All Atari computers except the original ST and Mega ST support both horizontal and vertical fine scrolling in hardware. To accomplish this, an application must place a special handler in the vertical blank vector (at 0x00000070) which resets the scroll registers and video base address as needed.

The following registers are manipulated during the vertical-blank period to shift the screen across any number of virtual 'screens':

Register | Address | Contents
--- | --- | ---
VBASEHI | 0xFFFF8200 | Low byte contains bits 23-16 of the video display base address.
VBASEMID | 0xFFFF8202 | Low byte contains bits 15-8 of the video display base address.
VBASELO | 0xFFFF820C | Low byte contains bits 7-0 of the video display base address.
LINEWID | 0xFFFF820E | Number of extra WORDs per scanline (normally 0).
HSCROLL | 0xFFFF8264 | Low four bits contain the bitwise offset (0-15) of the screen (normally 0 unless scrolling is in effect).
VCOUNTHI | 0xFFFF8204 | Low byte contains bits 23-16 of the current video refresh address (use with care).
VCOUNTMID | 0xFFFF8206 | Low byte contains bits 15-8 of the current video refresh address (use with care).
VCOUNTLO | 0xFFFF8208 | Low byte contains bits 7-0 of the current video refresh address (use with care).

To accommodate virtual screens wider than the display can show, set LINEWID to the number of extra WORDs per scanline. For instance, to create a virtual display two screens wide for a 320x200 16-color display, set LINEWID to 80.

To scroll vertically, simply alter the video base address by adding or subtracting the number of WORDs per scanline for each line you wish to scroll during the vertical blank.

To scroll horizontally, alter the video base address in WORD increments to move the physical screen left and right over the virtual screen. This by itself will cause the screen to skip in 16 pixel jumps. To scroll smoothly, use the HSCROLL register to shift the display accordingly. When HSCROLL is non-zero, subtract one from LINEWID for each plane.

To illustrate this more clearly, imagine a physical screen of 320x200 (16 colors) which is laid out over 4 virtual screens in a 2x2 grid. The following diagram and table shows example values to move the physical screen to the desired virtual coordinates:

Sample Values
Virtual Coordinates | VBASE Address | LINEWID | HSCROLL
( 0, 0 ) | 0x80000 | 80 | 0
( 16, 0 ) | 0x80004 | 80 | 0
( 0, 1 ) | 0x80140 | 80 | 0
( 1, 0 ) | 0x80000 | 76 | 1
( 0, 10 ) | 0x80B40 | 80 | 0
( 100, 100 ) | 0x87BE4 | 76 | 4

Table of Contents | Index