MEMORY MAP

Locations zero to 255 ($0 to $FF) are called "page zero" and have special importance for assembly language programmers since these locations are accessed faster and easier by the machine. Locations zero to 127 ($0 to $7F) are reserved as the OS page zero, while 128 to 255 ($80 to $FF) are the BASIC and the user zero page RAM. Locations zero to 1792 ($0 to $700) are all used as the OS and (if the cartridge is present) 8K BASIC RAM (except page six). Locations zero to 8191 ($0 to $1FFF) are the minimum required for operation (8K). Locations two through seven are not cleared on any start operation.

DECIMAL HEX LABEL

0,1 0,1 LINZBS

LINBUG RAM, replaced by the monitor RAM See the OS Listing, page 31. It seems to be used to store the VBLANK timer value. One user application I've seen for location zero is in a metronome program in De Re Atari. Also used in cross- assembling the Atari OS.

2,3 2,3 CASINI

Cassette initialization vector: JSR through here if the cassette boot was successful. This address is extracted from the first six bytes of a cassette boot file. The first byte is ignored. The second contains the number of records, the third and fourth contain the low and high bytes of the load address, and the fifth and sixth contain the low and high bytes of the initialization address. Control upon loading jumps to the load address plus six for a multi-stage load and through CASINI for initialization. JSR through DOSVEC (10 and 11; $A,$B) to transfer control to the application.

4,5 4,5 RAMLO

RAM pointer for the memory test used on powerup. Also used to store the disk boot address--normally 1798 ($706)--for the boot continuation routine.

6 6 TRAMSZ

Temporary Register for RAM size; used during powerup sequence to test RAM availability. This value is then moved to RAMTOP, location 106 ($6A). Reads one when the BASIC or the A (left) cartridge is plugged in.

7 7 TSTDAT

RAM test data register. Reads one when the B or the right cartridge is inserted. RAMLO, TRAMSZ and TSTDAT are all used in testing the RAM size on powerup. On DOS boot, RAMLO and TRAMSZ also act as temporary storage for the boot continuation address. TRAMSZ and TSTDAT are used later to flag whether or not the A (left) and/or B (right) cartridges, respectively, are plugged in (non- zero equals cartridge plugged in) and whether the disk is to be hooted. Locations eight through 15 ($8-$F) are cleared on coldstart only.

8 8 WARMST

Warmstart flag. If the location reads zero, then it is in the middle of powerup; 255 is the normal RESET status. Warmstart is similar to pressing RESET, so should not wipe out memory, variables, or programs. WARMST is initialized to zero and will not change values unless POKEd or until the first time the RESET button is pressed. It will then read 255 ($FF). Warmstart normally vectors to location 58484 ($E474). WARMST is checked by the NMI status register at 54287 ($D40F) when RESET is pressed to see whether or not to re-initialize the software or to re-boot the disk.

9 9 BOOT?

Boot flag success indicator. A value of 255 in this location will cause the system to lockup if RESET is pressed. If BOOT? reads one, then the disk boot was successful; if it reads two, then the cassette boot was successful. If it reads zero, then neither peripheral was booted. If it is set to two, then the cassette vector at locations two and three will be used on RESET. Set to one, it will use the DOS vector at 10 and 11 ($A and $B). Coldstart attempts both a cassette and a disk boot and flags this location with the success or failure of the boots. BOOT? is checked during both disk and cassette boot.

10,11 A,B DOSVEC

Start vector for disk (or non-cartridge) software. This is the address BASIC jumps to when you call up DOS. Can be set by user to point to your own routine, but RESET will return DOSVEC to the original address. To prevent this, POKE 5446 with the LSB and 5450 with the MSB of your vector address and re-save DOS using the WRITE DOS FILES option in the menu. Locations 10 and 11 are usually loaded with 159 and 23 ($9F and $17), respectively. This allows the DUPSYS section of DOS to be loaded when called. It is initially set to blackboard mode vector (58481; $E471--called by typing "BYE" or "B." from BASIC); it will also vector to the cassette run address if no DOS vector is loaded in. If you create an AUTORUN.SYS file that doesn't end with an RTS instruction, you should set BOOT? to one and 580 ($244) to zero.

12,13 C,D DOSINI

Initialization address for the disk boot. Also used to store the cassette-boot RUN address, which is then moved to CASINI (2, 3). When you powerup without either the disk or an autoboot cassette tape, DOSINI will read zero in both locations.

14,15 E,F APPMHI

Applications memory high limit and pointer to the end of your BASIC program, used by both the OS and BASIC. It contains the lowest address you can use to set up a screen and Display List (which is also the highest address usable for programs and data below which the display RAM may not be placed). The screen handler will not OPEN the "S:" device if it would extend the screen RAM or the Display List below this address; memory above this address may be used for the screen display and other data (PM graphics, etc.). If an attempted screen mode change would extend the screen memory below APPMHI, then the screen is set up for GRAPHICS mode zero; MEMTOP (locations 741, 742; $2E5, $2E6) is updated and an error is returned to the user. Otherwise, the memory is not too small for the screen editor; the mode change will take effect and MEMTOP will be updated. This is one of five locations used by the OS to keep track of the user and display memory. Initialized to zero by the OS at powerup. Remember, you cannot set up a screen display below the location specified here. If you use the area below the Display List for your character sets, PM graphics or whatever, be sure to set APPMHI above the last address used so that the screen or the DL data will not descend and destroy your own data. See RAMTOP location 106 ($6A), MEMTOP at 741, 742 ($2E5, $2E6), PMBASE at 54279 ($D407) and CHBASE at 54281 ($D409) for more information. Locations 16 through 127 ($10-$7F) are cleared on either cold- or warmstart.

16 10 POKMSK

POKEY interrupts: the IRQ service uses and alters this location. Shadow for 53774 ($D20E). POKE with 112 ($70; also POKE this same value into 53774) to disable the BREAK key. If the following bits are set (to one), then these interrupts are enabled (bit decimal values are in parentheses): BIT DECIMAL FUNCTION 7 128 The BREAK key is enabled. 6 64 The "other key" interrupt is enabled. 5 32 The serial input data ready interrupt is enabled. 4 16 The serial output data required interrupt is enabled. 3 8 The serial out transmission finished interrupt is enabled. 2 4 The POKEY timer four interrupt is enabled (only in the "B" or later versions of the OS ROMs). 1 2 The POKEY timer two interrupt is enabled. 0 1 The POKEY timer one interrupt is enabled. Timer interrupt enable means the associated AUDF registers are used as timers and will generate an interrupt request when they have counted down to zero. See locations 528 to 535 ($210 to $217) and the POKEY chip from locations 53760 ($D200) on, for a full explanation. 192 ($C0) is the default on powerup. You can also disable the BREAK key by POKEing here with 64 ($40; or any number less than 128; $80) and also in location 53774. The problem with simple POKEs is that the BREAK key is re-enabled when RESET is pressed and by the first PRINT statement that displays to the screen, or any OPEN statement that addresses the screen (S: or E:), or the first PRINT statement after such an OPEN and any GRAPHICS command. In order to continually disable the BREAK key if such commands are being used, it's best to use a subroutine that checks the enable bits frequently during input and output operations, and POKEs a value less than 128 into the proper locations, such as: 1000 BREAK = PEEK(16) - 128: IF BREA K < 0 THEN RETURN 1010 POKE 16, BREAK: POKE 53774, BRE AK: RETURN The new OS "B" version ROMs have a vector for the BREAK key interrupt, which allows users to write their own routines to process the interrupt in the desired manner. It is located at 566, 567 ($236, $237).

17 11 BRKKEY

Zero means the BREAK key is pressed; any other number means it's not. A BREAK during I/O returns 128 ($80). Monitored by both keyboard, display, cassette and screen handlers. See location 16 ($A) for hints on disabling the BREAK key. The latest editions of OS provide for a proper vector for BREAK interrupts. The BREAK key abort status code is stored in STATUS (48; $30). It is also checked during all I/O and scroll/draw routines. During the keyboard handler routine, the status code is stored in DSTAT (76; $4C). BRKKEY is turned off at powerup. BREAK key abort status is flagged by setting BIT 7 of 53774 ($D20E). See the note on the BREAK key vector, above.

18,19,20 12,13,14 RTCLOK

Internal realtime clock. Location 20 increments every stage one VBLANK interrupt (1/60 second = one jiffy) until it reaches 255 ($FF); then location 19 is incremented by one and 20 is reset to zero (every 4.27 seconds). When location 19 reaches 255, it and 20 are reset to zero and location 18 is incremented by one (every 18.2 minutes or 65536 TV frames). To use these locations as a timer of seconds, try: TIME = INT((PEEK(18) * 65536 + PEEK(19) * 256 + PEEK(20) )/60) To see the count in jiffies, eliminate the "/60" at the end. To see the count in minutes, change "/60" to "/360." The maximum value of the RT clock is 16,777,215. When it reaches this value, it will be reset to zero on the next VBLANK increment. This value is the result of cubing 256 (i.e., 256 * 256 * 256), the maximum number of increments in each clock register. The RT clock is always updated every VBLANK regardless of the time-critical nature of the code being processed. A jiffy is actually a long time to the computer. It can perform upwards of 8000 machine cycles in that time. Think of what can be done in the VBLANK interval (one jiffy). In human terms, a jiffy can be upwards of 20 minutes, as witnessed in the phrase "I'll be ready in a jiffy." Compare this to the oft-quoted phrase, "I'll be there in a minute," used by intent programmers to describe a time frame upwards of one hour. Users can POKE these clock registers with suitable values for their own use. The realtime clock is always updated during the VBLANK interval. Some of the other timer registers (locations 536 to 544; $218 to $220) are not always updated when the OS is executing time critical code. Here's one way to use the realtime clock for a delay timer: 10 GOSUB 100 . . . 100 POKE 20,0: POKE 19,0 110 IF NOT PEEK(19) THEN 110 120 RETURN Line 110 waits to see if location 19 returns to zero and, when it does, passes control to the RETURN statement. See COMPUTE!, August 1982, for a useful program to create a small realtime clock that will continue to display during your BASIC programming. See also De Re Atari for another realtime clock application.

21,22 15,16 BUFADR

Indirect buffer address register (page zero). Temporary pointer to the current disk buffer.

23 17 ICCOMT

Command for CIO vector. Stores the CIO command; used to find the offset in the command table for the correct vector to the handler routine.

24,25 18,19 DSKFMS

Disk file manager pointer. Called JMPTBL by DOS; used as vector to FMS.

26,27 1A,1B DSKUTL

The disk utilities pointer. Called BUFADR by DOS, it points to the area saved for a buffer for the utilities package (data buffer; DBUF) or for the program area (MEMLO; 743, 744; $2E7, $2E8).

28 1C PTIMOT

Printer timeout, called every printer status request. Initialized to 30, which represents 32 seconds (the value is 64 seconds per 60 increments in this register); typical timeout for the Atari 825 printer is five seconds. The value is set by your printer handler software. It is updated after each printer status request operation. It gets the specific timeout status from location 748 ($2EC), which is loaded there by SIO. The new "B" type OS ROMs have apparently solved the problem of timeout that haunted the "A" ROMs; you saw it when the printer or the disk drive periodically went to sleep (timed out) for a few seconds, causing severe anxiety attacks in the owners who thought their Ataris had just mysteriously died. This is compounded when one removes a disk from the drive, believing the I/O process to be finished--only to have the drive start up again after the timeout and trying to write to or read from a nonexistent disk. Usually both the system and the user crash simultaneously at this point. See the appendix for more information on the new ROMs.

29 1D PBPNT

Print buffer pointer; points to the current position (byte) in the print buffer. Ranges from zero to the value in location 30.

30 1E PBUFSZ

Print buffer size of printer record for current mode. Normal buffer size and line size equals 40 bytes; double-width print equals 20 bytes (most printers use their own control codes for expanded print); sideways printing equals 29 bytes (Atari 820 printer only). Printer status request equals four. PBUFSZ is initialized to 40. The printer handler checks to see if the same value is in PBPNT and, if so, sends the contents of the buffer to the printer.

31 1F PTEMP

Temporary register used by the printer handler for the value of the character being output to the printer. ---------------------------------------------------------------------- Locations 32 to 47 ($20 to $2F) are the ZIOCB: Page zero Input-Output Control Block. They use the same structure as the IOCB's at locations 832 to 959 ($340 to $3BF). The ZIOCB is used to communicate I/O con- trol data between CIO and the device handlers. When a CIO opera- tion is initiated, the information stored in the IOCB channel is moved here for use by the CIO routines. When the operation is finished, the updated information is returned to the user area.

32 20 ICHIDZ

Handler index number. Set by the OS as an index to the device name table for the currently open file. If no file is open on this IOCB (IOCB free), then this register is set to 255 ($FF).

33 21 ICDNOZ

Device number or drive number Called MAXDEV by DOS to in- dicate the maximum number of devices. Initialized to one.

34 22 ICCOMZ

Command code byte set by the user to define how the rest of the IOCB is formatted, and what I/O action is to be performed.

35 23 ICSTAZ

Status of the last IOCB action returned by the device, set by the OS. May or may not be the same status returned by the STATUS command.

36,37 24,25 ICBALZ/HZ

Buffer address for data transfer or the address of the file name for commands such as OPEN, STATUS, etc.

38,39 26,27 ICPTLZ/HZ

Put byte routine address set by the OS. It is the address minus one byte of the device's "put one byte" routine. It points to CIO's "IOCB not OPEN" on a CLOSE statement.

40,41 28,29 ICBLLZ/HZ

Buffer length byte count used for PUT and GET operations; decreased by one for each byte transferred.

42 2A ICAX1Z

Auxiliary information first byte used in OPEN to specify the type of file access needed.

43 2B ICAX2Z

CIO working variables, also used by some serial port functions. Auxiliary information second byte.

44,45 2C,2D ICAX3Z/4Z

Used by BASIC NOTE and POINT commands for the transfer of disk sector numbers. These next four bytes to location 47 are also labelled as: ICSPRZ and are defined as spare bytes for local CIO use.

46 2E ICAX5Z

The byte being accessed within the sector noted in locations 44 and 45. It is also used for the IOCB Number multiplied by 16. Each IOCB block is 16 bytes long. Other sources indicate that the 6502 X register also contains this information.

47 2F ICAX6Z

Spare byte. Also labelled CIOCHR, it is the temporary storage for the character byte in the current PUT operation. -------------------------------------------------------------------

48 30 STATUS

Internal status storage. The SIO routines in ROM use this byte to store the status of the current SIO operation. See page 166 of the OS User's Manual for status values. STATUS uses location 793 ($319) as temporary storage. STATUS is also used as a storage register for the timeout, BREAK abort and error values during SIO routines.

49 31 CHKSUM

Data frame checksum used by SIO: single byte sum with carry to the least significant bit. Checksum is the value of the number of bytes transmitted (255; $FF). When the number of transmitted bytes equals the checksum, a checksum sent flag is set at location 59 ($3B). Uses locations 53773 ($D20D) and 56 ($38) for com- parison of values (bytes transmitted).

50,51 32,33 BUFRLO/HI

Pointer to the data buffer, the contents of which are transmitted during an I/O operation, used by SIO and the Device Control Block (DCB); points to the byte to send or receive. Bytes are transferred to the eight-bit parallel serial output holding register or from the input holding register at 53773 ($D20D). This register is a one-byte location used to hold the eight bits which will be transmitted one bit at a time (serially) to or from the device. The computer takes the eight bits for processing when the register is full or replaces another byte in it when empty after a transmission.

52,53 34,35 BFENLO/HI

Next byte past the end of the SIO and DCB data buffer described above.

54 36 CRETRY

Number of command frame retries. Default is 13 ($0D). This is the number of times a device will attempt to carry out a command such as read a sector or format a disk.

55 37 DRETRY

Number of device retries. The default is one.

56 38 BUFRFL

Data buffer full flag (255; $FF equals full).

57 39 RECVDN

Receive done flag (255; $FF equals done).

58 3A XMTDON

Transmission done flag (255; $FF equals done).

59 3B CHKSNT

Checksum sent flag (255; $FF equals sent).

60 3C NOCKSM

Flag for "no checksum follows data." Not zero means no checksum follows; zero equals checksum follows transmission data.

61 3D BPTR

Cassette buffer pointer: record data index into the portion of data being read or written. Ranges from zero to the current value at location 650 ($28A). When these values are equal, the buffer at 1021 ($3FD) is empty if reading or full if writing. Initialized to 128 ($80).

62 3E FTYPE

Inter-record gap type between cassette records, copied from location 43 ($2B; ICAX2Z) in the ZIOCB, stored there from DAUX2 (779; $30B) by the user. Normal gaps are a non-zero positive number; continuous gaps are zero (negative number).

63 3F FEOF

Cassette end of file flag. If the value is zero, an end of file (EOF) has not been reached. Any other number means it has been detected. An EOF record has been reached when the command byte of a data record equals 254 ($FE). See location 1021 ($3FD).

64 40 FREQ

Beep count retain register. Counts the number of beeps required by the cassette handler during the OPEN command for play or record operations; one beep for play, two for record.

65 41 SOUNDR

Noisy I/O flag used by SIO to signal the beeping heard during disk and cassette I/O. POKE here with zero for blessed silence during these operations. Other numbers return the beep. In- itialized to three. The hardware solution to this problem is to turn your speaker volume down. This can also be used to silence the digital track when playing synchronized voice/data tapes. See location 54018.

66 42 CRITIC

Critical I/O region flag; defines the current operation as a time- critical section when the value here is non-zero. Checked at the NMI process after the stage one VBLANK has been processed. POKEing any number other than zero here will disable the repeat action of the keys and change the sound of the CTRL-2 buzzer. Zero is normal; setting CRITIC to a non-zero value suspends a number of OS processes including system software timer coun- ting (timers two, three, four and five; see locations 536 to 558; $218 to $22E). It is suggested that you do not set CRITIC for any length of time. When one timer is being set, CRITIC stops the other timers to do so, causing a tiny amount of time to be "lost." When CRITIC is zero, both stage one and stage two VBLANK procedures will be executed. When non-zero, only the stage one VBLANK will be processed.

67-73 43-49 FMZSPG

Disk file manager system (FMS) page zero registers (seven bytes).

67,68 43,44 ZBUFP

Page zero buffer pointer to the user filename for disk I/O.

69,70 45,46 ZDRVA

Page zero drive pointer. Copied to here from DBUFAL and DBUFAH; 4905 and 4913 ($1329, $1331). Also used in FMS "free sector," setup and "get sector" routines.

71,72 47,48 ZSBA

Zero page sector buffer pointer.

73 49 ERRNO

Disk I/O error number. Initialized to 159 ($9F) by FMS.

74 4A CKEY

Cassette boot request flag on coldstart. Checks to see if the START key is pressed and, if so, CKEY is set. Autoboot cassettes are loaded by pressing the START console key while turning the power on. In response to the beep, press the PLAY button on the recorder.

75 4B CASSBT

Cassette boot flag. The Atari attempts both a disk and a cassette boot simultaneously. Zero here means no cassette boot was suc- cessful. See location 9

76 4C DSTAT

Display status and keyboard register used by the display handler. Also used to indicate memory is too small for the screen mode, cursor out of range error, and the BREAK abort status.

77 4D ATRACT

Attract mode timer and flag. Attract mode rotates colors on your screen at low luminance levels when the computer is on but no keyboard input is read for a long time (seven to nine minutes). This helps to save your TV screen from "burn-out" damage suf- fered from being left on and not used. It is set to zero by IRQ whenever a key is pressed, otherwise incremented every four seconds by VBLANK (see locations 18 - 20; $12 - $14). When the value in ATRACT reaches 127 ($7F), it is then set to 254 ($FE) un- til attract mode is terminated. This sets the flag to reduce the luminance and rotate the colors when the Atari is sitting idle. POKE with 128 ($80) to see this effect immediately: it normally takes seven to nine minutes to enable the attract mode. The OS cannot "attract" color generated by DLI's, although your DLI routine can, at a loss of time. Joysticks alone will not reset location 77 to zero. You will have to add a POKE 77,0 to your program periodically or frequently call in a subroutine to prevent the Atari from entering attract mode if you are not using any keyboard input.

78 4E DRKMSK

Dark attract mask; set to 254 ($FE) for normal brightness when the attract mode is inactive (see location 77). Set to 246 ($F6) when the attract mode is active to guarantee screen color luminance will not exceed 50% . Initialized to 254 ($FE).

79 4F COLRSH

Color shift mask; attract color shifter; the color registers are EORd with locations 78 and 79 at the stage two VBLANK (see locations 18 - 20; $12 - $14). When set to zero and location 78 equals 246, color luminance is reduced 50%. COLRSH contains the current value of location 19, therefore is given a new color value every 4.27 seconds. Bytes 80 to 122 ($50 to $7A) are used by the screen editor and display handler.

80 50 TEMP

Temporary register used by the display handler in moving data to and from screen. Also called TMPCHR.

81 51 HOLD1

Same as location 80. It is used also to hold the number of Display List entries.

82 52 LMARGN

Column of the left margin of text (GR.0 or text window only). Zero is the value for the left edge of the screen; LMARGN is initialized to two. You can POKE the margin locations to set them to your specific program needs, such as POKE 82,10 to make the left margin start ten locations from the edge of the screen.

83 53 RMARGN

Right margin of the text screen initialized to 39 ($27). Both locations 82 and 83 are user-alterable, but ignored in all GRAPHICS modes except zero and the text window. Margins work with the text window and blackboard mode and are reset to their default values by pressing RESET. Margins have no effect on scrolling or the printer. However, DELETE LINE and INSERT LINE keys delete or insert 40 character lines (or delete one program line), which always start at the left margin and wrap around the screen edge back to the left margin again. The right margin is ignored in the process. Also, logical lines are always three physical lines no matter how long or short you make those lines. The beep you hear when you are coming to the end of the logical line works by screen position independent of the margins. Try setting your left margin at 25 (POKE 82,25) and typing a few lines of characters. Although you have just a few characters beyond 60, the buzzer will still sound on the third line of text.

84 54 ROWCRS

Current graphics or text screen cursor row, value ranging from zero to 191 ($BF) depending on the current GRAPHICS mode (maximum number of rows, minus one). This location, together with location 85 below, defines the cursor location for the next element to be read/written to the screen. Rows run horizontally, left to right across the TV screen. Row zero is the topmost line; row 192 is the maximum value for the bottom-most line.

85,86 55,56 COLCRS

Current graphics or text mode cursor column; values range from zero to 319 (high byte, for screen mode eight) depending on current GRAPHICS mode (maximum numher of columns minus one). Location 86 will always be zero in modes zero through seven. Home position is 0,0 (upper left-hand corner). Columns run vertically from the top to the bottom down the TV screen, the leftmost column being number zero, the rightmost column the maximum value in that mode. The cursor has a complete top to bottom, left to right wraparound on the screen. ROWCRS and COLCRS define the cursor location for the next element to be read from or written to in the main screen segment of the display. For the text window cursor, values in locations 656 to 667 ($290 to $29B) are exchanged with the current values in locations 84 to 95 ($54 to $5F), and location 123 ($7B) is set to 255 ($FF) to indicate the swap has taken place. ROWCRS and COLCRS are also used in the DRAW and FILL functions to contain the values of the endpoint of the line being drawn. The color of the line is kept in location 763 ($2FB). These values are loaded into locations 96 to 98 ($60 to $62) so that ROWCRS and COLCRS may be altered during the operation. BASIC's LOCATE statement not only examines the screen, but also moves the cursor one position to the right at the next PRINT or PUT statement. It does this by updating locations 84 and 85, above. You can override the cursor advance by saving the contents of the screen before the LOCATE command, then restoring them after the LOCATE. Try: 100 REM: THE SCREEN MUST HAVE BEEN 0 PENED FOR READ OR READ/WRITE PREV IOUSLY 110 LOOK = PEEK(84): SEE = PEEK(85) 120 LOCATE X,Y,THIS 130 POKE 84, LOOK: POKE 65, SEE Note that CHR$(253) is a non-printing character---the bell-- and doesn't affect the cursor position. See COMPUTE!, August 198l, for an example of using COLCRS for dynamic data restore and updating with the screen editor and the IOCBs.

87 57 DINDEX

Display mode/current screen mode. Labelled CRMODE by (*M). DINDEX contains the number obtained from the low order four bits of most recent open AUX1 byte. It can be used to fool the OS into thinking you are in a different GRAPHICS mode by POKEing DINDEX with a number from zero to 11. POKE with seven after you have entered GRAPHICS mode eight, and it will give you a split screen with mode seven on top and mode eight below. However, in order to use both halves of the screen, you will have to modify location 89 (below) to point to the area of the screen you wish to DRAW in. (See Your Atan 400/800, pp. 280 - 283.) Watch for the cursor out-of-range errors (number 141) when changing GRAPHICS modes in this manner and either PRINTing or DRAWing to the new mode screen. POKE 87 with the BASIC mode number, not the ANTIC mode number. Did you know you can use PLOT and DRAWTO in GR.0? Try this: 10 GR.0 20 PLOT 0,0: DRAWTO 10,10: DRAWTO 0 ,10 30 DRAWTO 39,0: DRAWTO 20,23: DRAWT O 0,20 40 GOTO 40 You can also set the text window for PRINT and PLOT modes by POKEing 87 with the graphics mode for the window. Then you must POKE the address of the top left corner of the text window into 88 and 89 ($58, $59). The screen mode of the text window is stored at location 659 ($293). You may have already discovered that you cannot call up the GTIA modes from a direct command. Like the + 16 GRAPHICS modes, they can only be called up during a program, and the screen display will be reset to GR.0 on the first INPUT or PRINT (not PRINT#6) statement executed in these modes. Since this location only takes BASIC modes, you can't POKE it with the other ANTIC modes such as "E", the famous "seven-and- a-half" mode which offers higher resolution than seven and a four color display (used in Datasoft's Micropainter program). If you're not drawing to the screen, simply using it for display purposes, you can always go into the Display List and change the instructions there. But if you try to draw to the screen, you risk an out-of-bounds error (error number 141). See Creative Computing, March 1982, for an excellent look at mode 7.5. The short subroutine below can be used to change the Display List to GR.7.5: 1000 GRAPHICS 8+16: DLIST = PEEK(560) ) + PEEK(561) * 256:POKE DLIST + 3,78 1010 FOR CHANGE = DLIST + 6 TO DLIST + 204: IF PEEK(CHANGE) = 15 THE N POKE CHANGE,14 1020 IF PEEK (CHANGE) = 79 THEN POKE CHANGE,78: NEXT CHANGE 1030 POKE 87,7:RETURN DOWNLOAD MODE75.BAS (Actually, 15 ($F) is the DL number for the maximum memory mode; it also indicates modes eight through eleven. The DL's for these modes are identical.) Fourteen is the ANTIC E mode; GR.7.5 This program merely changes GR.8 to mode E in the Display List. The value 79 is 64 + 15; mode eight screen with BIT 6 set for a Load Memory Scan (LMS) instruction (see the DL information in locations 560, 561; $230, $231). It does not check for other DL bits. You can also POKE 87 with the GTIA values (nine to eleven). To get a pseudo-text window in GTIA modes, POKE the mode number here and then POKE 623 with 64 for mode nine, 128 for mode ten, and 192 for mode eleven, then POKE 703 with four, in program mode. (In command mode, you will be returned to GR.0.) You won't be able to read the text in the window, but you will be able to write to it. However, to get a true text window, you'll need to use a Display List Interrupt (see COMPUTE!, September 1982). If you don't have the GTIA chip, it is still possible to simulate those GRAPHICS modes by using DINDEX with changes to the Display List Interrupt. See COMPUTE!, July 1981, for an example of simulating GR.10.

88,89 58,59 SAVMSC

The lowest address of the screen memory, corresponding to the upper left corner of the screen (where the value at this address will be displayed). The upper left corner of the text window is stored at locations 660, 661 ($294, $295). You can verify this for yourself by: WINDOW = PEEK(88) + PEEK(89) * 256: POKE WINDOW,33 This will put the letter "A" in the upper left corner in GR.0, 1 and 2. In other GRAPHICS modes, it will print a colored block or bar. To see this effect, try: 5 REM FIRST CLEAR SCREEN 10 GRAPHICS Z: IF Z > 59 THEN END 15 SCREEN = PEEK (88) + PEEK (89) * 256 20 FOR N = 0 TO 255: POKE SCREEN + N ,N 25 NEXT N: FOR N = 1 TO 300: NEXT N: Z = Z + 1 30 GOTO 10 DOWNLOAD SAVEMSC1.BAS You will notice that you get the Atari internal character code, not the ATASCII code. See also locations 560, 561 ($230, $231) and 57344 ($E000). How do you find the entire screen RAM? First, look at the chart below and find your GRAPHICS mode. Then you multiply the number of rows-per-screen type by the number of bytes-per-line. This will tell you how many bytes each screen uses. Add this value, minus one, to the address specified by SAVMSC. However, if you subtract MEMTOP (locations 741, 742; $2E5, $2E6) from RAMTOP (106; $6A * 256 for the number of bytes), you will see that there is more memory reserved than just the screen area. The extra is taken up by the display list or the text window, or is simply not used (see the second chart below). Mode 0 1 2 3 4 5 6 7 8 9-12 Rows Full 24 24 12 24 48 48 96 96 192 192 Split -- 20 10 20 40 40 80 80 160 -- Bytes per Line 40 20 20 10 10 20 20 40 40 40 Columns per Line 40 20 20 40 80 80 160 160 320 80 Memory (1) 993 513 261 273 537 1017 2025 3945 7900 7900 Memory (2) Full 992 672 420 432 696 1176 2184 4200 8138 8138 Split -- 674 424 434 694 1174 2174 4190 8112 -- (1) According to the Atari BASIC Reference Manual, p.45; OS User's Manual, p.172, and Your Atari 400/800, p.360. (2) According to Your Atari 400/800, p.274, and Atari Microsoft Basic Manual, p.69. This is also the value you get when you subtract MEMTOP from RAMTOP (see above). For example, to POKE the entire screen RAM in GR.4, you would find the start address of the screen (PEEK(88) + PEEK(89) * 256), then use a FOR-NEXT loop to POKE all the locations specified above: 10 GRAPHICS 4: SCRN = PEEK(88) + PE EK(89) * 256 20 FOR LOOP = SCRN to SCRN + 479: R EM 48 ROWS * 10 BYTES - 1 30 POKE LOOP,35: NEXT LOOP DOWNLOAD SAVEMSC2.BAS Why the minus one in the calculation? The first byte of the screen is the first byte in the loop. If we add the total size, we will go one byte past the end of the soreen, so we subtract one from the total. Here's how to arrive at the value for the total amount ot memory located for screen use, display list and Text window: Total memory allocation for the screen Screen display Display List ----------------------------------------------------------- Text unused bytes screen unused used GR window always cond. use bytes bytes Total ----------------------------------------------------------- 0 ... none none 960 none 32 992 1 160 none 80 400 none 34 674 2 160 none 40 200 none 24 424 3 160 none 40 200 none 34 434 4 160 none 80 400 none 54 694 5 160 none 160 800 none 54 1174 6 160 none 320 1600 none 94 2174 7 160 none 640 3200 96 94 4190 8 160 16 1280 6400 80 176 8112 The number of bytes from RAMTOP (location 106; $6A) is counted from the left text window column towards the total column. MEMTOP (741, 742; $2E5, $2E6) points to one byte below RAMTOP * 256 minus the number of bytes in the total column. If 16 is added to the GRAPHICS mode (no text window), then the conditional unused bytes are added to the total. Then the bytes normally added for the text window become unused, and the Display List expands slightly. (See COMPUTE!, September 1981.) When you normally PRINT CHR$(125) (clear screen), Atari sends zeroes to the memory starting at locations 88 and 89. It continues to do this until it reaches one byte less than the contents of RAMTQP (location 106; $6A). Here is a potential source of conflict with your program, however: CHR$(125)--CLEAR SCREEN--and any GRAPHICS command actually continue to clear the first 64 ($40) bytes above RAMTOP! It would have no effect on BASIC since BASIC is a ROM cartridge. The OS Source Listing seems to indicate that it ends at RAMTOP, but Atari assumed that there would be nothing after RAMTOP, so no checks were provided. Don't reserve any data within 64 bytes of RAMTOP or else it will be eaten by the CLEAR SCREEN routine, or avoid using a CLEAR SCREEN or a GRAPHICS command. Scrolling the text window also clears 800 bytes of memory above RAMTOP. You can use this to clear other areas of memory by POKEing the LSB and MSB of the area to be cleared into these locations. Your routine should always end on a $FF boundary (RAMTOP indicates the number of pages). Remember to POKE back the proper screen locations or use a GRAPHICS command immediately after doing so to set the screen right. Try this: 10 BOTTOM = 30000: TOP = 36863: REM LOWEST AND HIGHEST ADDRESS TO CLEA R = $7530 & $8FFF 20 RAMTOP = PEEK(106): POKE 106, INT (TOP + 1 / 256) 30 TEST = INT(BOTTOM / 256): POKE89, TEST 40 POKE 88. BOTTOM - 256 * TEST 50 PRINT CHR$(125): POKE 106, RAMTOP 60 GRAPHICS 0 DOWNLOAD SAVEMSC3.BAS This will clear the specified memory area and update the address of screen memory. If you don't specify TOP, the CLEAR SCREEN will continue merrily cleaning out memory and, most likely, will cause your program to crash. Use it with caution. Here's a means to SAVE your current GR.7 screen display to disk using BASIC: 1000 SCREEN = PEEK(88) + PEEK(89) * 256 1010 OPEN #2,8,0,"D:picturename" 1020 MODE = PEEK(87): PUT #2, MODE: REM SAVE GR. MODE 1030 FOR SCN = 0 TO 4: COL PEEK(70 8 + SCN): PUT #2,COL: NEXT SCN: REM SAVE COLOR REGISTERS 1040 FOR TV = SCREEN TO SCREEN + 319 9:BYTE = PEEK(TV): PUT #2, BYTE: NEXT TV: CLOSE #2 DOWNLOAD SAVEMSC4.BAS To use this with other screen modes, you will have to change the value of 3199 in line 1040 to suit your screen RAM (see the chart above). For example, GR.7 + 16 would require 3839 bytes (3840 minus one). You can use the same routine with cassette by using device C:. To retrieve your picture, you use GET#2 and POKE commands. You will, however, find both routines very slow. Using THE CIO routine at 58454 ($E456) and the IOCBs, try this machine language save routine: 10 DIM ML$(10): B$(10): GR.8+16 20 B$ = "your picture name":Q = PEEK (559) 30 FOR N = 1 TO 6: READ BYTE: ML$(N, N) = CHR$(BYTE): NEXT N 35 DATA 104,162,16,76,86,228 36 REM PLA,LDX,$10,JMP $E456 40 OPEN #1,4,0,B$ 50 POKE 849,1: POKE 850,7: POKE 852, PEEK(88): POKE 853,PEEK(89): POKE 856,70: POKE 857,30: POKE 858,4 55 REM THESE POKES SET UP THE IOCB 60 POKE 559,0: REM TURN OFF THE SCRE EN TO SPEED THINGS UP 70 X = USR(ADR(ML$)): CLOSE #1 80 POKE 559,Q: REM TURN IT BACK ON A GAIN DOWNLOAD SAVEMSC5.BAS Note that there is no provision to SAVE the color registers in this program, so I suggest you have them SAVEd after you have SAVEd the picture. It will make it easier to retrieve them if they are at the end of the file. You will have to make suitable adjustments when SAVEing a picture in other than GR.8 + 16 -- such as changing the total amount of screen memory to be SAVEd, POKEd into 856 and 857. Also, you will need a line such as 1000 GOTO 1000 to keep a GTIA or + 16 mode screen intact. See the Atari column in InfoAge Magazine, July 1982, for more on this idea. See location 54277 ($D405) for some ideas on scrolling the screen RAM. ------------------------------------------------------------------------ A SHORT DIGRESSION There are two techniques used in this hook for calling a machine language program from BASIC with the USR command. One method is to POKE the values into a specific address -- say, page six -- and use the starting address for the USR call, such as X = USR(1536). For an example of this technique, see location 632 ($278). The other technique, used above, is to make a string (ML$) out of the routine by assigning to the elements of the string the decimal equivalents of the machine language code by using a FOR-NEXT and READ-DATA loop. To call this routine, you would use X = USR(ADR(ML$)). This tells the Atari to call the machine language routine located at the address where ML$ is stored. This address will change with program size and memory use. The string method won't be overwritten by another routine or data since it floats around safely in memory. The address of the string itself is stored by the string/array table at location 140 ($8C). ------------------------------------------------------------------------

90 5A OLDROW

Previous graphics cursor row. Updated from location 84 ($54) before every operation. Used to determine the starting row for the DRAWTO and XIO 18 (FILL command).

91,92 5B,5C OLDCOL

Previous graphics cursor column. Updated from locations 85 and 86 ($55, $56) before every operation. These locations are used by the DRAWTO and XIO 18 (FILL) commands to determine the starting column of the DRAW or FILL

93 5D OLDCHR

Retains the value of the character under the cursor used to restore that character when the cursor moves

94,95 5E,5F OLDADR

Retains the memory location of the current cursor location. Used with location 93 (above) to restore the character under the cursor when the cursor moves

96 60 NEWROW

Point (row) to which DRAWTO and XIO 18 (FILL) will go.

97,98 61,62 NEWCOL

Point (column) to which DRAWTO and XIO 18 (FILL) will go. NEWROW and NEWCOL are initialized to the values in ROWCRS and COLCRS (84 to 86; $54 to $56) above, which represent the destination end point of the DRAW and FILL functions. This is done so that ROWCRS and COLCRS can be altered during these routines.

99 63 LOGCOL

Position of the cursor at the column in a logical line. A logical line can contain up to three physical lines, so LOGCOL can range between zero and 119. Used by the display handler.

100,101 64,65 ADRESS

Temporary storage used by the display handler for the Display List address, line buffer (583 to 622; $247 to $26E), new MEMTOP value after DL entry, row column address, DMASK value, data to the right of cursor, scroll, delete, the clear screen routine and for the screen address memory (locations 88, 89; $58, $59).

102,103 66,67 MLTTMP

Also called OPNTMP and TOADR; first byte used in OPEN as temporary storage. Also used by the display handler as temporary storage.

104,105 68,69 SAVADR

Also called FRMADR. Temporary storage, used with ADRESS above for the data under the cursor and in moving line data on the screen.

106 6A RAMTOP

RAM size, defined by powerup as passed from TRAMSZ (location 6), given in the total number of available pages (one page equals 256 bytes, so PEEK(106) * 256 will tell you where the Atari thinks the last usable address --byte-- of RAM is). MEMIOP (741, 742; $2E5. $2E6) may not extend below this value. In a 48K Atari, RAMTOP is initialized to 160 ($A0), which points to location 40960 ($A000). The user's highest address will be one byte less than this value. This is initially the same value as in location 740. PEEK(740) / 4 or PEEK(106) / 4 gives the number of 1K blocks. You can fool the computer into thinking you have less memory than you actually have, thus reserving a relatively safe area for data (for your new character set or player/missile characters, for example) or machine language subroutines by: POKE(106), PEEK(106) - # of pages you want to reserve. The value here is the number of memory pages (256-byte blocks) present. This is useful to know when changing GR.7 and GR.8 screen RAM. If you are reserving memory for PM graphics, POKE 54279, PEEK(106) - # of pages you are reserving before you actually POKE 106 with that value. To test to see if you have exceeded your memory by reserving too much memory space, you can use: 10 SIZE = (PEEK(106) - # of pages) * 256 20 IF SIZE < = PEEK(144) + PEEK(145 ) * 256 THEN PRINT "TOO MUCH MEMOR Y USED" If you move RAMTOP to reserve memory, always issue a GRAPHICS command (even issuing one to the same GRAPHICS mode you are in will work) immediately so that the display list and data are moved beneath the new RAMTOP. You should note that a GRAPHICS command and a CLEAR command (or PRINT CHR$(125)) actually clear the first 64 bytes above RAMTOP (see location 88; $58 for further discussion). Scrolling the text window of a GRAPHICS mode clears up to 800 ($320) bytes above RAMTOP (the text window scroll actually scrolls an entire GR.0 screen-worth of data, so the unseen 20 lines * 40 bytes equals 800 bytes). PM graphics may be safe (unless you scroll the text window) since the first 384 or 768 bytes (double or single line resolution, respectively) are unused. However, you should take both of these effects into account when writing your programs. To discover the exact end of memory, use this routine (it's a tad slow): 10 RAMTOP = 106: TOP = PEEK(RAMTOP) 20 BYTE = TOP * 256: TEST = 255 - PE EK(BYTE): POKE BYTE,TEST 30 IF PEEK(BYTE) = TEST THEN TOP = T OP +1: POKE BYTE, 255 - TEST 40 GOTO 20 50 PRINT "MEMORY ENDS AT "; BYTE One caution: BASIC cannot always handle setting up a display list and display memory for GRAPHICS 7 and GRAPHICS 8 when you modify this location by less than 4K (16 pages; 4096 bytes). Some bizarre results may occur if you use PEEK(106) - 8 in these modes, for example. Use a minimum of 4K (PEEK(106) - 16) to avoid trouble. This may explain why some people have difficulties with player/missile graphics in the hi-res (high resolution; GR.7 and GR.8) modes. See location 54279 ($D407). Another alternative to reserving memory in high RAM is to save an area below MEMLO, location 743 ($2E7: below your BASIC program). See also MEMTOP, locations 741, 742 ($2E5, $2E6).

107 6B BUFCNT

Buffer count: the screen editor current logical line size counter.

108,109 6C,6D BUFSTR

Editor low byte (AM). Display editor GETCH routine pointer (location 62867 for entry; $F593). Temporary storage; returns the character pointed to by BUFCNT above.

110 6E BITMSK

Bit mask used in bit mapping routines by the OS display handler at locations 64235 to 64305 ($FAEB to $FB31). Also used as a display handler temporary storage register.

111 6F SHFAMT

Pixel justification: the amount to shift the right justified pixel data on output or the amount to shift the input data to right justify it. Prior to the justification process, this value is always the same as that in 672 ($2A0).

112,113 70,71 ROWAC

ROWAC and COLAC (below) are both working accumulators for the control of row and column point plotting and the increment and decrement functions.

114,115 72,73 COLAC

Controls column point plotting.

116,117 74,75 ENDPT

End point of the line to be drawn. Contains the larger value of either DELTAR or DELTAC (locations 118 and 119, below) to be used in conjunction with ROWAC/COLAC (locations 112 and 114, above) to control the plotting of line points.

118 76 DELTAR

Delta row; contains the absolute value of NEWBOW (location 96; $60) minus ROWCRS (location 84; $54).

119,120 77,78 DELTAC

Delta column; contains the absolute value of NEWCOL (location 97; $61) minus the value in COLCRS (location 85; $55). These delta register values, along with locations 121 and 122 below, are used to define the slope of the line to be drawn.

121 79 ROWINC

The row increment or decrement value (plus or minus one).

122 7A COLINC

The column increment or decrement value (plus or minus one). ROWINC and COLINC control the direction of the line drawing routine. The values represent the signs derived from the value in NEWROW (location 96; $60) minus the value in ROWCRS (location 84; $54) and the value in NEWCOL (locations 97, 98; $61, $62) minus the value in COLCRS (locations 85, 86; $55, $56).

123 7B SWPFLG

Split-screen cursor control. Equal to 255 ($FF) if the text window RAM and regular RAM are swapped; otherwise, it is equal to zero. In split-screen modes, the graphics cursor data and the text window data are frequently swapped in order to get the values associated with the area being accessed into the OS data base locations 84 to 95 ($54 to $5F). SWPFLG helps to keep track of which data set is in these locations.

124 7C HOLDCH

A character value is moved here before the control and shift logic are processed for it.

125 7D INSDAT

Temporary storage byte used by the display handler for the character under the cursor and end of line detection.

126,127 7E,7F COUNTR

Starts out containing the larger value of either DELTAR (location 118; $76) or DELTAC (location 119; $77). This is the number of iterations required to draw a line. As each point on a line is drawn, this value is decremented. When the byte equals zero, the line is complete (drawn). --------------------------------------------------------------------- User and/or BASIC page zero RAM begins here. Locations 128 to 145 ($80 to $91) are for BASIC program pointers; 146 to 202 ($92 to $CA) are for miscellaneous BASIC RAM; 203 to 209 ($CB to $D1) are unused by BASIC, and 210 to 255 ($D2 to $FF) are the floating point routine work area. The Assembler Editor cartridge uses locations 128 to 176 ($80 to $B0) for its page zero RAM. Since the OS doesn't use this area, you are free to use it in any non-BASIC or non-cartridge environment. If you are using another language such as FORTH, check that program's memory map to see if any conflict will occur. See COMPUTE!'s First Book of Atari, pages 26 to 53, for a discussion of Atari BASIC structure, especially that using locations 130 to 137 ($82 to $89). Included in the tutorials are a memory analysis, a line dump, and a renumber utility. See also De Re Atari, BYTE, February 1982, and the locations for the BASIC ROM 40960 to 49151 ($A000 to $BFFF).

128,129 80,81 LOMEM

Pointer to BASIC's low memory (at the high end of OS RAM space). The first 256 bytes of the memory pointed to are the token output buffer, which is used by BASIC to convert BASIC statements into numeric representation (tokens; see locations 136, 137; $88, $89). This value is loaded from MEMLO (locations 743, 744; $2E7, $2E8) on initialization or the execution of a NEW command (not on RESET!). Remember to update this value when changing MEMLO to reserve space for drivers or buffers. When a BASIC SAVE is made, two blocks of information are written: the first block is the seven pointers from LOMEM to STARP (128 to 141; $80 to $8D). The value of LOMEM is subtracted from each of these two-byte pointers in the process, so the first two bytes written will both be zero. The second block contains the following: the variable name table, the variable value table, the tokenized program, and the immediate mode line. When a BASIC LOAD is made, BASIC adds the value at MEMLO (743, 744; $2E7, $2E8) to each of the two-byte pointers SAVEd as above. The pointers are placed back in page zero, and the values of RUNSTK (142, 143; $8E, $8F) and MEMTOP (144, 145; $90, $91) are set to the value in STARP. Then 256 bytes are reserved above the value in MEMLO for the token output buffer, and the program is read in immediately following this buffer. When you don't have DOS or any other application program using low memory loaded, LOMEM points to 1792 ($700). When DOS 2.0 is present, it points to 7420 ($1CFC). When you change your drive and data buffer defaults (see 1801, 1802; $709, $70A), you will raise or lower this figure by 128 bytes for each buffer added or deleted, respectively. When you boot up the RS-232 handler, add another 1728 ($6C0) bytes used. LOMEM is also called ARGOPS by BASIC when used in expression evaluation. When BASIC encounters any kind of expression, it puts the immediate results into a stack. ARGOPS points to the same 256 byte area; for this operation it is reserved for both the argument and operator stack. It is also called OUTBUFF for another operation, pointing to the same 256 byte buffer as ARGOPS points to. Used by BASIC when checking a line for syntax and converting it to tokens. This buffer temporarily stores the tokens before moving them to the program.

130,131 82,83 VNTP

Beginning address of the variable name table. Variable names are stored in the order input into your program, in ATASCII format. You can have up to 128 variable names. These are stored as tokens representing the variable number in the tokenized BASIC program, numbered from 128 to 255 ($80 to $FF). The table continues to store variable names, even those no longer used in your program and those used in direct mode entry. It is not cleared by SAVEing your program. LOADing a new program replaces the current VNT with the one it retrieves from the file. You must LIST the program to tape or disk to save your program without these unwanted variables from the table. LIST does not SAVE the variable name or variable value tables with your program. It stores the program in ATASCII, not tokenized form, and requires an ENTER command to retrieve it. You would use a NEW statement to clear the VNT in memory once you have LISTed your program. Each variable name is stored in the order it was entered, not the ATASCII order. With numeric (scalar) variables, the MSB is set on the last character in a name. With string variables, the last character is a "$" with the MSB (BIT 7) set. With array variables, the last character is a "(" with the MSB set. Setting the MSB turns the character into its inverse representation so it can be easily recognized. You can use variable names for GOSUB and GOTO routines, such as: 10 CALCULATE = 1000 . . 100 GOSUB CALCULATE This can save a lot of bytes for a frequently called routine. But remember, each variable used for a GOSUB or GOTO address uses one of the 128 possible variable names. A disadvantage of using variable names for GOTO and GOSUB references is when you try to use a line renumbering program. Line renumbering programs will not change references to lines with variable names, only to lines with numbered references. Here's a small routine you can add to the start of your BASIC program (or the end if you change the line numbers) to print out the variable names used in your program. You call it up with a GOTO statement in direct mode: 1 POKE 1664, PEEK(130): POKE 1665, PEEK (131) 2 IF PEEK(1664) = PEEK(132) THEN IF PEEK(1665) = PEEK(133) THEN STOP 3 PRINT CHR$(PEEK(PEEK(1664) + PEEK (1665) * 256))); 4 IF PEEK(PEEK(1664) + PEEK(1665) * 256)) > 127 THEN PRINT""; 5 IF PEEK(1664) = 255 THEN POKE 166 4, 0: POKE 1665, PEEK(1665) + 1: GO TO 2 6 POKE 1664, PEEK(1664) + 1: GOTO 2 DOWNLOAD VNTP.BAS See COMPUTE!, October 1981.

132,133 84,85 VNTD

Pointer to the ending address of the variable name table plus one byte. When fewer than 128 variables are present, it points to a dummy zero byte. When 128 variables are present, this points to the last byte of the last variable name, plus one. It is often useful to be able to list your program variables; using locations 130 to 133, you can do that by: 10 VARI = PEEK(130) + PEEK(131) * 2 56 :REM This gives you the start o f the table. 20 FOR VARI = VARI TO PEEK(132) + P EEK(133) * 256 - 1: PRINT CHR$(PEE K(VARI) - 128 * PEEK(VARI > 127)); CHR$(27 + 128 * PEEK(VARI) > 127) );:NEXT VARI 25 REM this finds the end of the va ri able name table (remember table is end + 1). then PRINTs ASCII cha racters < 128 30 NUM = 0: FOR VARI = PEEK(130) + PEEK(313) * 256 TO PEEK(132) + PEE K(131) * 256 - 1:NUM = NUM + (PEEK (VARI) < 127):NEXT VARI: PRINT NU M; "Variables in use" DOWNLOAD VNTD1.BAS Or try this, for a possibly less opaque example of the same routine: 1000 NUM = 0: FOR LOOP = PEEK (130) + PEEK(131) * 256 TO PEEK(132) + PEEK(133) * 256 - 1 1010 IF PEEK(LOOP) < 128 THEN PRINT CHR$(PEEK(LOOP));: GOTO 1030 1020 PRINT CHR$(PEEK(LOOP) - 128): N UM - NUM + 1 1030 NEXT LOOP: PRINT; PRINT NUM; " VARIABLES IN USE": END DOWNLOAD VNTD2.BAS

134,135 86,87 VVTP

Address for the variable value table. Eight bytes are allocated for each variable in the name table as follows: Byte 1 2 3 4 5 6 7 8 Variable -------------------------------------------------------------- Scalar 00 var # six byte BCD constant Array;DIMed 65 var # offset first second unDIMed 64 from DIM + 1 DIM + 1 STARP String;DIMed 129 var # offset length DIM unDIMed 128 from STARP In scalar (undimensioned numeric) variables, bytes three to eight are the FP number; byte three is the exponent; byte four contains the least significant two decimal digits, and byte eight contains the most significant two decimal digits. In array variables, bytes five and six contain the size plus one of the first dimension of the array (DIM + 1; LSB/MSB), and bytes seven and eight contain the size plus one of the second dimension (the second DIM + 1; LSB/MSB). In string variables, bytes five and six contain the current length of the variable (LSB MSB), and bytes seven and eight contain the actual dimension (up to 32767). There is an undocumented BASIC statement, "COM," mentioned only in the BASIC Reference Manual's index, which executes exactly the same as the "DIM" statement (see Your Atari 400/800, p.346). Originally, it was to be used to implement "common" variables. In all cases, the first byte is always one of the number listed on the chart above (you will seldom, if ever, see the undimensioned values in a program). This number defines what type of variable information will follow. The next byte, var # (variable number), is in the range from zero to 127. Offset is the number of bytes from the beginning of STARP at locations 140 and 141 ($8C, $8D). Since each variable is assigned eight bytes, you could find the values for each variable by: 1000 VVTP = PEEK(134) + PEEK(135) * 256: INPUT VAR: REM VARIABLE NUM BER 1010 FOR LOOP = 0 TO 7: PRINT PEEK(V VTP + LOOP + 8 * VAR): NEXT LOOP where VAR is the variable number from zero to 127. If you wish to assign the same value to every element in a DIMed string variable use this simple technique: 10 DIM TEST$(100) 20 TEST$ = "*": REM or use TEST$(1) 30 TEST$(100) = TEST$ 40 TEST$(2) = TEST$: PRINT TEST$ By assigning the first, last and second variables in the array in that order, your Atari will then assign the same value to the rest of the array. Make sure you make the second and last elements equal to the string, not the character value (i.e don't use TEXT$(2) = "*"). See De Re Atari for an example of SAVEing the six-byte BCD numbers to a disk file -- very useful when dealing with fixed record lengths.

136,137 88,89 STMTAB

The address of the statement table (which is the beginning of the user's BASIC program), containing all the tokenized lines of code plus the immediate mode lines entered by the user. Line numbers are stored as two-byte integers, and immediate mode lines are given the default value of line 32768 ($8000). The first two bytes of a tokenized line are the line number, and the next is a dummy byte reserved for the byte count (or offset) from the start of this line to the start of the next line. Following that is another count byte for the start of this line to the start of the next statement. These count values are set only when tokenization for the line and statement are complete. Tokenization takes place in a 256 byte ($100) buffer that resides at the end of the reserved OS RAM (pointed to by locations 128, 129; $80, $81). To see the starting address of your BASIC line numbers use this routine: 10 STMTAB = PEEK(136) + PEEK(137)*2 56 20 NUM = PEEK(STMTAB) + PEEK (STMTAB +1)*256 30 IF NUM = 32768 THEN END 40 PRINT"LINE NUMBER: ";NUM;" ADDRE SS: ";STMTAB 50 STMTAB = STMTAB + PEEK(STMTAB+2) 60 GOTO 20 The August 1982 issue of ANTIC provided a useful program to delete a range of BASIC line numbers. The routine can be appended to your program and even be used to delete itself.

138,139 8A,8B STMCUR

Current BASIC statement pointer, used to access the tokens being currently processed within a line of the statement table. When BASIC is awaiting input, this pointer is set to the beginning of the immediate mode (line 32768). Using the address of the variable name table, the length, and the current statement (locations 130 to 133, 138, 139), here is a way to protect your programs from being LISTed or LOADed: they can only be RUN! Remember, that restricts you too, so make sure you have SAVEd an unchanqed version before you do this: 32000 FOR VARI = PEEK(130) + PEEK(1 31) * 256 TO PEEK(132) + PEEK(1 33) * 256:POKE VARI,155:NEXT VA RI 32100 POKE PEEK(138) + PEEK(139) * 256 + 2,0: SAVE "D:filename": N EW This will cause all variable names to be replaced with a RETURN character. Other characters may be used: simply change 155 for the appropriate ATASCII code for the character desired. Make sure that these are the last two lines of your program and that NEW is the last statement. CLOAD will not work, but a filename with C: will.

140,141 8C,8D STARP

The address for the string and array table and a pointer to the end of your BASIC program. Arrays are stored as six-byte binary coded decimal numbers (BCD) while string characters use one bye each. The address of the strings in the table are the same as those returned by the BASIC ADR function. Always use this function under program control, since the addresses in the table change according to your program size. Try: 10 DIM A$(10),B$(10) 20 A$ = "*": A$(10) = A$: A$(2) = A $ 30 B$ = "&": B$(10) = B$: B$(2) = B $ 40 PRINT ADR(A$), ADR(B$) 50 PRINT PEEK(140) + PEEK(141) * 25 6: REM ADDRESS OF A$ 60 PRINT PEEK(140) + PEEK(141) * 25 6 + 10: REM ADRESS OF A$ + 10 BYTE S = ADDRESS OF B$ This table is expanded as each dimension is processed by BASIC, reducing available memory. A ten-element numeric array will require 60 bytes for storage. An array variable such as DIM A(100) will cost the program 600 bytes (100 * six per dimensioned number equals 600). On the other hand, a string array such as DIM A$(100) will only cost 100 bytes! It would save a lot of memory to write your arrays as strings and retrieve the array values using the VAL statement. For example: 10 DIM A$(10): A$ = "1234567890" 20 PRINT VAL(A$) 30 PRINT VAL(A$(4,4)) 40 PRINT VAL(A$(3,3))+VAL(A$(8,9)) See COMPUTE!, June 1982, for a discussion of STARP and VVTP. See De Re Atari for a means to SAVE the string/array area with your program.

142,143 8E,8F RUNSTK

Address of the runtime stack which holds the GOSUB entries (four bytes each) and the FOR-NEXT entries (16 bytes each). The POP command in BASIC affects this stack, pulling entries off it one at a time for each POP executed. The stack expands and contracts as necessary while the program is running. Each GOSUB entry consists of four bytes in this order: a zero to indicate a GOSUB, a two-byte integer line number on which the call occurred, and an offset into that line so the RETURN can come back and execute the next statement. Each FOR-NEXT entry contains 16 bytes in this order: first, the limit the counter variable can reach; second, the step or counter increment. These two are allocated six bytes each in BCD format (12 bytes total). The 13th byte is the counter variable number with the MSB set; the 14th and 15th are the line number and the 16th is the line offset to the FOR statement. RUNSTK is also called ENDSTAR; it is used by BASIC to point to the end of the string/array space pointed to by STARR above.

144,145 90,91 MEMTOP

Pointer to the top of BASIC memory, the end of the space the program takes up. There may still be space between this address and the display list, the size of which may be retrieved by the FRE(0) command (which actually subtracts the MEMTOP value that is at locations 741 and 742; $2E5, $2E6). Not to be confused with locations 741 and 742, which have the same name but are an OS variable. MEMTOP is also called TOPSTK; it points to the top of the stack space pointed to by RUNSTK above. When reserving memory using location 106 ($6A) and MEMTOP, here's a short error-trapping routine you can add: 10 SIZE = (PEEK(106) - # of pages yo u are reserving) * 256 20 IF SIZE < = PEEK(144) + PEEK(145 ) * 256 THEN PRINT " PROGRAM TOO L ARGE": END Locations 146 to 202 ($92 to $CA) are reserved for use by the 8K BASIC ROM. Locations 176 to 207 ($B0 to $CF) are reserved by the Assembler Editor cartridge for the user's page zero use. The Assembler debug routine also reserves 30 bytes in page zero, scattered from location 164 ($A4) to 255 ($FF), but they cannot be used outside the debug process. (See De Re Atari, Rev. 1, Appendix A for a list of these available bytes.)

186,187 BA,BB STOPLN

The line where a program was stopped either due to an error or the use of the BREAK key, or a STOP or a TRAP statement occurred. You can use PEEK (186) + PEEK (187) * 256 in a GOTO or GOSUB statement.

195 C3 ERRSAVE

The number of the error code that caused the stop or the TRAP. You can use this location in a program in a line such as: 10 IF PEEK(195) <> 144 THEN 100

201 C9 PTABW

This location specifies the number of columns between TAB stops. The first tab will beat PEEK(201). The default is ten. This is the value between items separated in a PRINT statement by com- mas -- such as PRINT AS, LOOP, C(12) -- not by the TAB key spacing. The minimum number of spaces between TABS is three. If you POKE 201,2, it will be treated as four spaces, and POKE 201,1 is treated as three spaces. POKE 201,0 will cause the system to hang when it encounters a PRINT statement with commas. To change the TAB key settings, see TABMAP (locations 675 to 689; $2A3 - $2B1). PTABW is not reset to the default value by pressing RESET or changing GRAPHICS modes (unlike TABMAP). PTABW works in all GRAPHICS modes, not merely in text modes. The size of the spaces between items depends on the pixel size in the GRAPHICS mode in use. For example, in GR.0, each space is one character wide, while in GR.8 each space is one-half color clock (one dot) wide.

203-207 CB-CF ....

Unused by either the BASIC or the Assembler cartridges.

208-209 D0-D1 ....

Unused by BASIC. The only time I have seen any of these unused locations in use is in COMPUTE! (March 1982 and October 1981), when they were used for user sort routines, and in ANTIC (June 1982), where they were used as flags in a graphic demonstration. The bytes from 203 to 209 ($CB to $D1) are the only page zero bytes uncontestably left free by BASIC.

210-211 D2-D3 ....

Reserved for BASIC or other cartridge use. Locations 212 to 255 ($D4 to $FF) are reserved for the floating point package use. The FP routines are in ROM, from locations 55296 to 57393 ($D800 to $E031). These page zero locations may be used if the FP package is not called by the user's program. However, do not use any of these locations for an interrupt routine, since such routines might occur during an FP routine called by BASIC, causing the system to crash. Floating Point uses a six-byte precision. The first byte of the Binary Coded Decimal (BCD) number is the exponent (where if BIT 7 equals zero, then the number is positive; if one, then it is negative). The next five bytes are the mantissa. If only that were all there was to it. The BCD format is rather complex and is best explained in chapter eight of De Re Atari.

212-217 D4-D9 FR0

Floating point register zero; holds a six-byte internal form of the FP number. The value at locations 212 and 213 are used to return a two-byte hexadecimal value in the range of zero to 65536 ($FFFF) to the BASIC program (low byte in 212, high byte in 213). The floating point package, if used, requires all locations from 212 to 255. All six bytes of FR0 can be used by a machine language routine, provided FR0 isn't used and no FP functions are used by that routine. To use 16 bit values in FP, you would place the two bytes of the number into the least two bytes of FR0 (212, 213; $D4, $D5), and then do a JSR to $D9AA (55722), which will convert the integer to its FP representation, leaving the result in FR0. To reverse this operation, do a JSR to $D9D2 (55762).

218-223 DA-DF FRE

FP extra register (?)

224-229 E0-E5 FR1

Floating point register one; holds a six-byte internal form of the FP number as does FR0. The FP package frequently transfers data between these two registers and uses both for two-number arithmetic operations.

230-235 E6-EB FR2

FP register two.

236 EC FRX

FP spare register.

237 ED EEXP

The value of E (the exponent).

238 EE NSIGN

The sign of the FP number.

239 EF ESIGN

The sign of the exponent.

240 F0 FCHRFLG

The first character flag. 241 Fl DIGRT The number of digits to the right of the decimal.

242 F2 CIX

Character (current input) index. Used as an offset to the input text buffer pointed to by INBUFF below.

243,244 F3,F4 INBUFF

Input ASCII text buffer pointer; the user's program line input buffer, used in the translation of ATASCII code to FP values. The result output buffer is at locations 1408 to 1535 ($580 to $5FF).

245,246 F5,F6 ZTEMP1

Temporary register.

247,248 F7,F8 ZTEMP4

Temporary register.

249,250 F9,FA ZTEMP3

Temporary register.

251 FB RADFLG

Also called DEGFLG. When set to zero, all of the trigonometric functions are performed in radians; when set to six, they are done in degrees. BASIC's NEW command and RESET both restore RADFLG to radians.

252,253 FC,FD FLPTR

Points to the user's FP number.

254,255 FE,FF FPTR2

Pointer to the user's second FP number to be used in an operation. End of the page zero RAM. ---------------------------------------------------------------------------

PAGE ONE: THE STACK

Locations 256 to 511 ($100 to $1FF) are the stack area for the OS, DOS and BASIC. This area is page one. Machine language JSR, PHA and interrupts all cause data to be written to page one, and RTS, PLA and RTI instructions all read data from page one. On powerup or RESET, the stack pointer is initialized to point to location 511 ($1FF). The stack then pushes downward with each entry to 256 ($100). In case of overflow, the stack will wrap around from 256 back to 511 again. ---------------------------------------------------------------------------

PAGES TWO TO FOUR

Locations 512 to 1151 ($200 to $47F) are used by the OS for working variables, tables and data buffers. In this area, locations 512 to 553 ($200 to $229) are used for interrupt vectors, and locations 554 to 623 ($22A to $26F) are for miscellaneous use. Much of pages two through five cannot be used except by the OS unless specifically noted. A number of bytes are marked as "spare", i.e., not in use currently. The status of these bytes may change with an Atari upgrade, so their use is not recommended. There are two types of interrupts: Non-Maskable Interrupts (NMI) processed by the ANTIC chip and Interrupt Requests (IRQ) processed by the POKEY and the PIA chips. NMI's are for the VBLANK interrupts (VBI's; 546 to 549, $222 to $225), display list interrupts (DLI) and RESET key interrupts. They initiate the stage one and stage two VBLANK procedures; usually vectored through an OS service routine, they can be vectored to point to a user routine. IRQ's are for the timer interrupts, peripheral and serial bus interrupts, BREAK and other key interrupts, and 6502 BRK instruction interrupts. They can usually be used to vector to user routines. See NMIST 54287 ($D40F) and IRQEN 53774 ($D20E) for more information. NMI interrupt vectors are marked NMI; IRQ interrupt vectors are marked IRQ. Refer to the chart below location 534 for a list of the interrupt vectors in the new OS "B" version ROMs.

512,513 200,201 VDSLST

The vector for NMI Display List Interrupts (DLI): containing the address of the instructions to be executed during a DLI (DLI's are used to interrupt the processor flow for a few microseconds at the particular screen display line where the bit was set, allowing you to do another short routine such as music, changing graphics modes, etc.). The OS doesn't use DLI's; they must be user- enabled, written and vectored through here. The NMI status register at 54287 ($D40F) first tests to see if an interrupt was caused by a DLI and, if so, jumps through VDSLST to the routine written by the user. DLI's are disabled on powerup, but VBI's are enabled (see 546 to 549; $222 to $225). VDSLST is initialized to point to 59315 ($E7B3), which is merely an RTI instruction. To enable DLI's, you must first POKE 54286 ($D40E) with 192 ($C0); otherwise, ANTIC will ignore your request. You then POKE 512 and 513 with the address (LSB/MSB) of the first assembly language routine to execute during the DLI. You must then set BIT 7 of the Display List instruction(s) where the DLI is to occur. You have only between 14 and 61 machine cycles available for your DLI, depending on your GRAPHICS mode. You must first push any 6502 registers onto the stack, and you must end your DLI with an RTI instruction. Because you are dealing with machine language for your DLI, you can POKE directly into the hardware registers you plan to change, rather than using the shadow registers that BASIC uses. There is, unfortunately, only one DLI vector address. If you use more than one DLI and they are to perform different activities, then changing the vectoring to point to a different routine must be done by the previous DLI's themselves. Another way to accomplish interrupts is during the VBLANK interval with a VBI. One small problem with using DLI's is that the keyboard "click" routine interferes with the DLI by throwing off the timing, since the click is provided by several calls to the WSYNC register at 54282 ($D40A). Chris Crawford discusses several solutions in De Re Atari, but the easiest of them is not to allow input from the keyboard! See Micro, December 1981, Creative Computing, July 1981 and December 1981. Here's a short example of a DLI. It will print the lower half of your text screen upside down: 10 START = PEEK(560) + PEEK(561) * 256: POKE START + 16,130 20 PAGE = 1536: FOR PGM = PAGE TO P AGE + 7: READ BYTE: POKE PGM, BYTE : NEXT PGM 30 DATA 72,169,4,141,1,212,104,64 40 POKE 512,0: POKE 513,6: POKE 542 86,192 50 FOR TEST = 1 TO 240: PRINT"SEE " ;: NEXT TEST 60 GOTO 60 DOWNLOAD VDSLST.BAS Another example of a DLI changes the color of the bottom half of the screen. To use it, simply change the PAGE + 7 to PAGE + 10 in the program above and replace line 30 with: 30 DATA 72,169,222,141,10,212,141,2 4,208,104,64 Finally, delete lines 50 and 60. See also location 54282 ($D40A).

514,515 202,203 VPRCED

Serial (peripheral) proceed line vector, initialized to 59314 ($E7B2), which is merely a PLA, RTI instruction sequence. It is used when an IRQ interrupt occurs due to the serial I/O bus proceed line which is available for peripheral use. According to De Re Atari, this interrupt is not used and points to a PLA, RTI instruction sequence. This interrupt is handled by the PIA chip and can be used to provide more control over external devices. See the OS Listing, page 33.

516,517 204,205 VINTER

Serial (peripheral) interrupt vector, initialized to 59314 ($E7B2). Used for the IRQ interrupt due to a serial bus I/O interrupt. According to De Re Atari, this interrupt is not used and points to a PLA, RTI sequence. This interrupt is processed by PIA. See the OS Listing, page 33.

518,519 206,207 VBREAK

Software break instruction vector for the 6502 BRK ($00) command (not the BREAK key, which is at location 17; $11), initialized to 59314 ($E7B2). This vector is normally used for setting break points in an assembly language debug operation. IRQ.

520,521 208,209 VKEYBD

POKEY keyboard interrupt vector, used for an interrupt generated when any keyboard key is pressed other than BREAK or the console buttons. Console buttons never generate an interrupt unless one is specifically user-written. VKEYBD can be used to process the key code before it undergoes conversion to ATASCII form. Initialized to 65470 ($FFBE) which is the OS keyboard IRQ routine.

522,523 20A,20B VSERIN

POKEY serial I/O bus receive data ready interrupt vector, initialized to 60177 ($EB11), which is the OS code to place a byte from the serial input port into a buffer. Called INTRVEC by DOS, it is used as an interrupt vector location for an SIO patch. DOS changes this vector to 6691 ($1A23), the start of the DOS interrupt ready service routine. IRQ.

524,525 20C,20D VSEROR

POKEY serial I/O transmit ready interrupt vector, initialized to 60048 (EA90), which is the OS code to provide the next byte in a buffer to the serial output port. DOS changes this vector to 6630 ($19E6), the start of the DOS output needed interrupt routine. IRQ.

526,527 20E,20F VSEROC

POKEY serial bus transmit complete interrupt vector, initialized to 60113 ($EAD1), which sets a transmission done flag after the checksum byte is sent. IRQ. SIO uses the three last interrupts to control serial bus communication with the serial bus devices. During serial bus communication, all program execution is halted. The actual serial I/O is interrupt driven; POKEY waits and watches for a flag to be set when the requested I/O operation is completed. During this wait, POKEY is sending or receiving bits along the seriai bus. When the entire byte has been transmitted (or received), the output needed (VSEROR) or the input ready (VSERIN) IRQ is generated according to the direction of the data flow. This causes the next byte to be processed until the entire buffer has been sent or is full, and a flag for "transmission done" is set. At this point, SIO exits back to the calling routine. You can see that SIO wastes time waiting for POKEY to send or receive the information on the bus.

528,529 210,211 VTIMR1

POKEY timer one interrupt vector, initialized to 59314 ($E7B2), which is a PLA, RTI instruction sequence. Timer interrupts are established when the POKEY timer AUDF1 (53760; $D200) counts down to zero. Values in the AUDF registers are loaded into STIMER at 53769 ($D209). IRQ.

530,531 212,213 VTIMR2

POKEY timer two vector for AUDF2 (53762, $D202), initialized to 59314 ($E7B2). IRQ.

532,533 214,215 VTIMR4

POKEY timer four vector for AUDF4 (53766, $D206), initialized to 59314 ($E7B2). This IRQ is only vectored in the "B" version of the OS ROMs.

534,535 216,217 VIMIRQ

The IRQ immediate vector (general). Initialized to 59126 ($E6F6). JMP through here to determine cause of the IRQ interrupt. Note that with the new ("B") OS ROMs, there is a BREAK key interrupt vector at locations 566, 567 ($236, $237). See 53774 ($D20E) for more information on IRQ interrupts. The new "B" version OS ROMs change the vectors above as follows: VDSLST 59280 ($E790) VPRCED 59279 ($E78F) VINTER 59279 ($E78F) VBREAK 59279 ($E78F) VKEYBD NO CHANGE VSERIN 60175 ($EB0F) VSEROR NO CHANGE VSEROC 60111 ($EACF) VTIMR 1-4 59279 ($E78F) VIMIRQ 59142 ($E706) VVBLKI 59310 ($E7AE) VVBLKD 59653 ($E905) --------------------------------------------------------------------------- The locations from 536 to 558 ($218 to $22E) are used for the system software timers. Hardware timers are located in the POKEY chip and use the AUDF registers. These timers count backwards every 1/60 second (stage one VBLANK) or 1/30 second (stage two VBLANK) interval until they reach zero. If the VBLANK process is disabled or intercepted, the timers will not be updated. See De Re Atari for information regarding setting these timers in an assembly routine using the SETVBV register (58460; $E45C). These locations are user- accessible and can be made to count time for music duration, game I/O, game clock and other functions. Software timers are used for durations greater than one VBLANK interval (1/60 second). For periods of shorter duration, use the hardware registers.

536,537 218,219 CDTMV1

System timer one value. Counts backwards from 255. This SIO timer is decremented every stage one VBLANK. When it reaches zero, it sets a flag to jump (JSR) through the address stored in locations 550, 551 ($226, $227). Only the realtime clock (locations 18-20; $12-14), timer one, and the attract mode register (77; $4D) are updated when the VBLANK routine is cut short because time-critical code (location 66; $42 set to non-zero for critical code) is executed by the OS. Since the OS uses timer one for its I/O routines and for timing serial bus operations (setting it to different values for timeout routines), you should use another timer to avoid conflicts or interference with the operation of the system.

538,539 21A,21B CDTMV2

System timer two. Decremented at the stage two VBLANK. Can be decremented every stage one VBLANK, subject to critical section test as defined by setting of CRITIC flag (location 66; $42). This timer may miss (skip) a count when time-critical code (CRITIC equals non-zero) is being executed. It performs a JSR through location 552, 553 ($228, $229) when the value counts down to zero.

540,541 21C,21D CDTMV3

System timer three. Same as 538. Timers three, four, and five are stopped when the OS sets the CRITIC flag to non-zero as well. The OS uses timer three to OPEN the cassette recorder and to set the length of time to read and write tape headers. Any prior value in the register during this function will be lost.

542,543 21E,21F CDTMV4

System timer four. Same as 538 ($21A).

544,545 220,221 CDTMV5

System timer five. Same as 538 ($21A). Timers three, four, and five all set flags at 554, 556 and 558 ($22A, $22C, $22E), respectively, when they decrement to zero.

546,547 222,223 VVBLKI

VBLANK immediate register. Normally jumps to the stage one VBLANK vector NMI interrupt processor at location 59345 ($E7D1); in the new OS "B" ROMs; 59310, $E7AE). The NMI status register tests to see if the interrupt was due to a VBI (after testing for a DLI) and, if so, vectors through here to the VBI routine, which may be user-written. On powerup, VBI's are enabled and DLI's are disabled. See location 512; $200.

548,549 224,225 VVBLKD

VBLANK deferred register; system return from interrupt, initialized to 59710 ($E93E, in the new OS "B" ROMs; 59653; $E905), the exit for the VBLANK routine. NMI. These two VBLANK vectors point to interrupt routines that occur at the beginning of the VBLANK time interval. The stage one VBLANK routine is executed; then location 66 ($42) is tested for the time-critical nature of the interrupt and, if a critical code section has been interrupted, the stage two VBLANK routine is not executed with a JMP made through the immediate vector VVBLKI. If not critical, the deferred interrupt VVBLKD is used. Normally the VBLANK interrupt bits are enabled (BIT 6 at location 54286; $D40E is set to one). To disable them, clear BIT 6 (set to zero). The normal seguence for VBLANK interrupt events is: after the OS test, JMP to the user immediate VBLANK interrupt routine through the vector at 546, 547 (above), then through SYSVBV at 58463 ($E45F). This is directed by the OS through the VBLANK interrupt service routine at 59345 ($E7D1) and then on to the user-deferred VBLANK interrupt routine vectored at 548, 549. it then exits the VBLANK interrupt routine through 58466 ($E462) and an RTI instruction. If you are changing the VBLANK vectors during the interrupt routine, use the SETVBV routine at 58460 ($E45C). An immediate VBI has about 3800 machine cycles of time to use a deferred VBI has about 20,000 cycles. Since many of these cycles are executed while the electron beam is being drawn, it is suggested that you do not execute graphics routines in deferred VBI's. See the table of VBLANK processes at the end of the map area. if you create your own VBI's, terminate an immediate VBI with a JMP to 58463 ($E45F) and a deferred VBI with a JMP to 58466 ($E462). To bypass the OS VBI routine at 59345 ($E7D1) entirely, terminate your immediate VBI with a JMP to 58466 ($E462). Here's an example of using a VBI to create a flashing cursor. It will also blink any text you display in inverse mode. 10 FOR BLINK = 1664 TO 1680: READ B YTE: POKE BLINK, BYTE: NEXT BLINK 20 POKE 548,128: POKE 549,6 30 DATA 8,72,165,20,41,16,74,74,74, 141 40 DATA 243,2,104,40,76,62,233 DOWNLOAD VVBLKD.BAS To restore the normal cursor and display, POKE 548,62 and POKE 549,233.

550,551 226,227 CDTMA1

System timer one jump address, initialized to 60400 ($EBF0). When locations 536, 537 ($218, $219) reach (count down to) zero, the OS vectors through here (jumps to the location specified by these two addresses). You can set your machine code routine address here for execution when timer one reaches (counts down to) zero. Your code should end with the RTS instruction. Problems may occur when timer values are set greater than 255, since the 6502 cannot manipulate 16-bit values directly (a number in the range of zero to 255 is an eight-bit value; if a value requires two bytes to store, such as a memory location, it is a 16-bit value). Technically, a VBLANK interrupt could occur when one timer byte is being initialized and the other not yet set. To avoid this, keep timer values less than 255. See the Atari OS User's Manual, page 106, for details. Since the OS uses timer one, it is recommended that you use timer two instead, to avoid conflicts with the operation of the Atari. Initialized to 60396 ($EBEA) in the old ROMs, 60400 ($EBF0) in the new ROMs. NMI

552,553 228,229 CDTMA2

System timer two jump address. Not used by the OS, available to user to enter the address of his or her own routine to JMP to when the timer two (538, 539; $21A, $21B) count reaches zero. Initialized to zero; the address must be user specified. NMI

554 22A CDTMF3

System timer three flag, set when location 540, 541 ($21C, $21D) reaches zero. This register is also used by DOS as a timeout flag.

555 22B SRTIMR

Software repeat timer, controlled by the IRQ device routine. It establishes the initial 1/2 second delay before a key will repeat. Stage two VBLANK establishes the 1/10 second repeat rate, decrements the timer and implements the auto repeat logic. Every time a key is pressed, STIMER is set to 48 ($30). Whenever SRTIMR is equal to zero and a key is being continuously pressed, the value of that key is continually stored in CH, location 764 ($2FC).

556 22C CDTMF4

System timer four flag. Set when location 542, 543 ($21E, $21F) counts down to zero.

557 22D INTEMP

Temporary register used by the SETVBL routine at 58460 ($E45C).

558 22E CDTMF5

System timer five flag. Set when location 558, 559 ($22E, $22F) counts down to zero. ---------------------------------------------------------------------------

559 22F SDMCTL

Direct Memory Access (DMA) enable. POKEing with zero allows you to turn off ANTIC and speed up processing by 30%. Of course, it also means the screen goes blank when ANTIC is turned off! This is useful to speed things up when you are doing a calculation that would take a long time. It is also handy to turn off the screen when loading a drawing, then turning it on when the screen is loaded so that it appears instantly, complete on the screen. To use it you must first PEEK(559) and save the result in order to return your screen to you. Then POKE 559,0 to turn off ANTIC. When you are ready to bring the screen back to life, POKE 559 with the number saved earlier. This location is the shadow register for 54272 ($D400), and the number you PEEKed above defines the playfield size, whether or not the missiles and players are enabled, and the player size resolution. To enable your options by using POKE 559, simply add up the values below to obtain the correct number to POKE into SDMCTL. Note that you must choose only one of the four playfield options appearing at the beginning of the list: Option Decimal Bit No playfield 0 0 Narrow playfield 1 0 Standard playfield 2 0,1 Wide playfield 3 0,1 Enable missle DMA 4 2 Enable player DMA 8 3 Enable player and missile DMA 12 2,3 One line player resolution 16 4 Enable instructions to fetch DMA 32 5 (see below) Note that two-line player resolution is the default and that it is not necessary to add a value to 559 to obtain it. I have included the appropriate bits affected in the table above. The default is 34 ($22). The playfield is the area of the TV screen you will use for display, text, and graphics. Narrow playfield is 128 color clocks (32 characters wide in GR.0), standard playfield is 160 color clocks (40 characters), and wide playfield is 192 color clocks wide (48 characters). A color clock is a physical measure of horizontal distance on the TV screen. There are a total of 228 color clocks on a line, but only some of these (usually 176 maximum) will be visible due to screen limitations. A pixel, on the other hand, is a logical unit which varies in size with the GRAPHICS mode. Due to the limitations of most TV sets, you will not be able to see all of the wide playfield unless you scroll into the offscreen portions. BIT 5 must be set to enable ANTIC operation; it enables DMA for fetching the display list instructions.

560,561 230,231 SDLSTL

Starting address of the display list. The display list is an instruction set to tell ANTIC where the screen data is and how to display it. These locations are the shadow for 54274 and 54275 ($D402, $D403). You can also find the address of the DL by PEEKing one byte above the top of free memory: PRINT PEEK(741) + PEEK(742) * 256 + 1. However, 560 and 561 are more reliable pointers since custom DL's can be elsewhere in memory. Atari standard display lists simply instruct the ANTIC chip as to which types of mode lines to use for a screen and where the screen data may be found in memory. Normally, a DL is between 24 and 256 bytes long (most are less than 100 bytes, however), depending on your GRAPHICS mode (see location 88,89 for a chart of DL sizes and screen display use). By altering the DL, you can mix graphics modes on the same screen; enable fine scrolling; change the location of the screen data; and force interrupts (DLI's) in order to perform short machine language routines. DL bytes five and six are the addresses of the screen memory data, the same as in locations 88 and 89 ($58, $59). Bytes four, five, and six are the first Load Memory Scan (LMS) instruction. Byte four tells ANTIC what mode to use; the next two bytes are the location of the first byte of the screen RAM (LSB/MSB). Knowing this location allows you to write directly to the screen by using POKE commands (you POKE the internal character codes, not the ATASCII codes -- see the BASIC Reference Manual, p. 55). For example, the program below will POKE the internal codes to the various screen modes. You can see not only how each screen mode handles the codes, but also roughly where the text window is in relation to the display screen (the 160 bytes below RAMTOP). Note that the GTIA modes have no text window. If you don't have the GTIA chip, your Atari will default to GRAPHICS 8, but with GTIA formatting. 1 TRAP 10: GRAPHICS Z 5 SCREEN = PEEK(560) + PEEK(561) * 256 6 TV = SCREEN + 4: TELE = SCREEN + 5 8 DISPLAY = PEEK(TV) + PEEK(TELE) * 256 10 FOR N = 0 TO 255: POKE DISPLAY + N,N: NEXT N 20 DISPLAY = DISPLAY + N 30 IF DISPLAY > 40959 THEN Z = Z + 1 : GOTO 1 40 GOTO 10 50 Z = Z + 1:IF Z > 60 THEN END 60 GOTO 1 Here's another short program which will allow you to examine the DL in any GRAPHICS mode: 10 REM CLEAR SCREEN FIRST 20 PRINT"ENTER GRAPHICS MODE": REM A DD 16 TO THE MODE TO SUPPRESS THE TEXT WINDOW 30 INPUT A: GRAPHICS A 40 DLIST = PEEK(560) + PEEIK(561) * 2 56 50 LOOK = PEEK(DLIST): PRINT LOOK;" "; 60 IF LOOK <> 65 THEN DLIST = DLIST + 1: GOTO 50 70 LPRINT PEEK(DLIST + 1);" ";PEEK(D LIST + 2) 80 END The value 65 in the DL is the last instruction encountered. It tells ANTIC to jump to the address in the next two bytes to re-execute the DL, and wait for the next VBLANK. If you don't have a printer, change the LPRINT commands to PRINT and modify the routine to save the data in an array and PRINT it to the screen after (in GR.0). If you would like to examine the locations of the start of the Display List, screen, and text window, try: 5 REM CLEAR SCREEN FIRST 6 INPUT A: GRAPHICS A 10 DIM DLIST$(10), SAVMSC$(10), TXT$ (10) 15 DLIST$ = "DLIST": SAVMSC$ = "SAVM SC": TXT$ = "TEXT" 20 DLIST = PEEK(560) + PEEK(561) * 2 56 30 SAV = PEEK(88) + PEEK(89) * 256: TXT = PEEK(660) + PEEK(66l) * 256 40 PRINT DLIST$;" "; DLIST,SAVMSC$;" ";SAV 50 PRINT TXT$;" "; TEXT 60 INPUT A: GRAPHICS A: GOTO 20 Since an LMS is simply a map mode (graphics) or character mode (text) instruction with BIT six set, you can make any or all of these instructions into LMS instructions quite easily, pointing each line to a different RAM area if necessary. This is discussed in De Re Atari on implementing horizontal scrolling. DL's can be used to help generate some of the ANTIC screen modes that aren't supported by BASIC, such as 7.5 (ANTIC mode E) or ANTIC mode three, the lowercase with descenders mode (very interesting; ten scan lines in height which allow true descenders on lowercase letters). If you create your own custom DL, you POKE its address here. Hitting BESET or changing GRAPHICS modes will restore the OS DL address, however. The display list instruction is loaded into a special register called the Display Instruction Register (IR). which processes the three DL instructions (blank, jump, or display). It cannot be accessed directly by the programmer in either BASIC or machine language. A DL cannot cross a 1K boundary unless a jump instruction is used. There are only four display list instructions: blank line (uses BAK color), map mode, text mode, and jump. Text (character mode) instructions and map mode (graphics) instructions range from two to 15 ($2 to $F) and are the same as the ANTIC GRAPHICS modes. A DL instruction byte uses the following conventions (functions are enabled when the bit is set to one): Bit Decimal Function 7 128 Display List Interrupt when set (enabled equals one) 6 64 Load Memory Scan. Next two bytes are the LSB/MSB of the data to load. 5 32 Enable vertical fine scrolling. 4 16 Enable horizontal fine scrolling. 3-0 8-1 Mode 0 0 1 0 Character to Modes 0 1 1 1 . . . . . . . 1 0 0 0 Map to Modes 1 1 1 1 The above bits may be combined (i.e., DLI, scrolling and LMS together) if the user wishes. Special DL instructions (with decimal values): Blank 1 line = 0 5 lines = 64 2 lines = 16 6 lines = 80 3 lines = 32 7 lines = 96 4 lines = 48 8 lines = 112 Jump instruction (JMP) = zero (three-byte instruction). Jump and wait for Vertical Blank (JVP) = 65 (three-byte instruction). Special instructions may be combined only with DL interrupt instructions. A Display List Interrupt is a special form of interrupt that takes place during the screen display when the ANTIC encounters a DL instruction with the interrupt BIT 7 set. See location 512 ($200) for DLI information. Since DL's are too large a topic to cover properly in this manual, I suggest you look in the many magazines (i.e., Creative Computing, July 1981, August 1981; Micro, December 1981; Softside, #30 to 32, and BYTE, December 1981) for a more detailed explanation

562 232 SSKCTL

Serial port control register, shadow for 53775 ($D20F). Setting the bits in this register to one has the following effect: Bit Decimal Function 0 1 Enable the keyboard debounce circuit. 1 2 Enable the keyboard scanning circuit. 2 4 The pot counter completes a read within two scan lines instead of one frame time. 3 8 Serial output transmitted as two-tone instead of logic true/false (POKEY two-tone mode). 4-6 16-64 Serial port mode control. 7 128 Force break; serial output to zero. Initialized to 19 ($13) which sets bits zero, one and four.

563 233 SPARE

No OS use. See the note at location 651 regarding spare bytes.

564 234 LPENH

Light pen horizontal value shadow for 54284 ($D40C). Values range from zero to 227.

565 235 LPENV

Light pen vertical value: shadow for 54285 ($D40D). Value is the same as VCOUNT register for two-line resolution (see 54283; $D40B). Both light pen values are modified when the trigger is pressed (pulled low). The light pen positions are not the same as the normal screen row and column positions. There are 96 vertical positions, numbered from 16 at the top to 111 at the bottom, each one equivalent to a scan line. Horizontal positions are marked in color clocks. There are 228 horizontal positions, numbered from 67 at the left. When the LPENH value reaches 255, it is reset to zero and begins counting again by one to the rightmost edge, which has a value of seven. Obviously, because of the number of positions readable and the small size of each, a certain leeway must be given by the programmer when using light pen readouts on a program. At the time of this writing, Atari had not yet released its light pen onto the market, although other companies have.

566,567 236,237 BRKKY

BREAK key interrupt vector. This vector is available only with the version "B" OS ROMs, not the earlier version. You can use this vector to write your own BREAK key interrupt routine. Initialized to 59220 ($E754).

568,569 238,239 ....

Two spare bytes.

570 23A CDEVIC

Four-byte command frame buffer (CFB) address for a device -- used by SIO while performing serial I/O, not for user access. CDEVIC is used for the SIO bus ID number The other three CFB bytes are:

571 23B CCOMND

The SIO bus command code.

572 23C CAUX1

Command auxiliary byte one, loaded from location 778 ($30A) by SIO.

573 23D CAUX2

Command auxiliary byte two, loaded from location 779 ($30B) by SIO.

574 23E TEMP

Temporary RAM register for SIO.

575 23F ERRFLG

SIO error flag; any device error except the timeout error (time equals zero).

576 240 DFLAGS

Disk flags read from the first byte of the boot file (sector one) of the disk.

577 241 DBSECT

The number of disk boot sectors read from the first disk record.

578,579 242,243 BOOTAD

The address for where the disk boot loader will be put. The record just read will be moved to the address specified here, followed by the remaining records to be read. Normally, with DOS, this address is 1792 ($700), the value also stored temporarily in RAMLO at 4, 5. Address 62189 ($F2ED) is the OS disk boot routine entry point (DOBOOT).

580 244 COLDST

Coldstart flag. Zero is normal, if zero, then pressing RESET will not result in reboot. If POKEd with one (powerup in progress flag), the computer will reboot whenever the RESET key is pressed. Any non-zero number indicates the initial powerup routine is in progress. If you create an AUTORUN.SYS file, it should end with an RTS instruction. If not, it should POKE 580 with zero and POKE 9 with one. You can turn any binary file that boots when loaded with DOS menu selection "L" into an auto-boot file simply by renaming it "AUTORUN.SYS". Be careful not to use the same name for any two files on the same disk. When this is combined with the disabling of the BREAK key discussed in location 16 ($10) and the program protection scheme discussed in location 138 ($8A), you have the means to protect your BASIC software fairly effectively from being LISTed or examined, although not from being copied.

581 245 ....

Spare byte.

582 246 DSKTIM

Disk time-out register (the address of the OS worst case disk time- out). It is said by many sources to be set to 160 at initialization which represents a 171 second time-out, but my system shows a value of 224 on initialization. Timer values are 64 seconds for each 60 units of measurement expressed. It is updated after each disk status request to contain the value of the third byte of the status frame (location 748; $2EC). All disk operations have a seven second time-out (except FORMAT), established by the disk handler (you had noticed that irritating little delay, hadn't you?). The "sleeping disk syndrome" (the printer suffers from this malady as well) happens when your drive times out, or the timer value reaches zero. This has been cured by the new OS "B" version ROMs.

583-622 247-26E LINBUF

Forty-byte character line buffer, used to temporarily buffer one physical line of text when the screen editor is moving screen data. The pointer to this buffer is stored in 100, 101 ($64, $65) during the routine.

623 26F GPRIOR

Priority selection register, shadow for 53275 ($D01B). Priority options select which screen objects will be "in front" of others. It also enables you to use all four missiles as a fifth player and allows certain overlapping players to have different colors in the areas of overlap. You add your options up as in location 559, prior to POKEing the total into 623. In this case, choose only one of the four priorities stated at the beginning. BAK is the background or border. You can also use this location to select one of GTIA GRAPHICS modes nine, ten, or eleven. Priority options in order Decimal Bit Player 0 - 3, playfield 0 - 3, BAK (background) 1 0 Player 0 - 1, playfield 0 - 3, player 2 - 3, BAK 2 1 Playfield 0 - 3, player 0 - 3, BAK 4 2 Playfield 0 - 1, player 0 - 3, playfield 2 -3, BAK 8 3 Other options Four missiles = fifth player 16 4 Overlaps of players have 3rd color 32 5 GRAPHICS 9 (GTIA mode) 64 6 GRAPHICS 10 (GTIA mode) 128 7 GRAPHICS 11 (GTIA mode) 192 6, 7 It is quite easy to set conflicting priorities for players and playfields. In such a case, areas where both overlap when a conflict occurs will turn black. The same happens if the overlap option is not chosen. With the color/overlap enable, you can get a multicolor player by combining players. The Atari performs a logical OR to colors of players 0/1 and 2/3 when they overlap. Only the 0/1, 2/3 combinations are allowed; you will not get a third color when players 1 and 3 overlap, for example (you will get black instead). If player one is pink and player 0 is blue, the overlap is green. If you don't enable the overlap option, the area of overlap for all players will be black. In GTIA mode nine, you have 16 different luminances of the same hue. In BASIC, you would use SETCOLOR 4,HUE,0. To see an example of GTIA mode nine, try: 10 GRAPHICS 9: SETCOLOR 4,9,0 20 FOR LOOP = 1 TO 15: COLOR LOOP 30 FOR LINE = 1 TO 2 40 FOR TEST = 1 TO 25: PLOT 4 + TES T, LOOP + LINE + SPACE: NEXT TEST 45 NEXT LINE 50 SPACE = SPACE + 4 60 NEXT LOOP 70 GOTO 70: REM WITHOUT THIS LINE, SCREEN WILL RETURN TO GR.0 DOWNLOAD GTIA9.BAS In GTIA mode ten, you have all nine color registers available; hue and luminance may be set separately for each (it would otherwise allow 16 colors, but there are only nine registers). Try this to see: 10 N = 0: GRAPHICS 10 20 FOR Q = 1 TO 2 30 FOR B = 0 TO 8: POKE 704 + B, N * 16 + A 35 IF A > 15 THEN A = 0 40 COLOR B 45 A = A + 1: N = N + 1 50 IF N > 15 THEN N = 0 60 NEXT B 65 TRAP 70: NEXT Q 70 POP: N = N + 1: FOR Z = 1 TO 200 : NEXT Z 75 GOTO 30 DOWNLOAD GTIA10.BAS GTIA mode eleven is similar to mode nine except that it allows 16 different hues, all of the same luminance. In BASIC, use SETCOLOR 4,O,luminance. Try this for a GTIA mode eleven demonstration: 10 GRAPHICS 11 20 FOR LOOP = 0 TO 79: COLOR LOOP: PLOT LOOP,0: DRAWTO LOOP,191: NEXT LOOP 30 GOTO 30 DOWNLOAD GTIA11.BAS You can use these examples with the routine to rotate colors, described in the text preceding location 704. GTIA mode pixels are long and skinny; they have a four to one horizontal length to height ratio. This obviously isn't very good for drawing curves and circles! GTIA modes are cleared on the OPEN command. How can you tell if you have the GTIA chip? Try POKE 623,64. If you have the GTIA, the screen will go all black. If not, you don't have it. Here is a short routine, written by Craig Chamberlain and Sheldon Leemon for COMPUTE!, which allows an Atari to test itself for the presence of a CTIA or GTIA chip. The routine flashes the answer on the screen, hut can easily be modified so a program will "know" which chip is present so it can adapt itself accordingly: 10 POKE 66,1:GRAPHICS 8:POKE 709,0:PO KE 710,0:POKE 66,0:POKE 623,64:P0K E 53248,42:POKE 5326l,3:PUT#6,1 20 POKE 53278,0:FOR K=1 TO 300:NEXT K :GRAPHICS 18:POKE 53248,0:POSITION 8,5:? #6;CHR$(71-PEEK(53252));"TI A" 30 POKE 708,PEEK(20):GOTO 30 DOWNLOAD CTIAGTIA.BAS How can you get the GTIA if you don't have one? Ask your local Atari service representative or dealer, or write directly to Atari in Sunnyvale, California. See the GTIA/CTIA introduction at location 53248 ($D000) for more discussion of the chip. See BYTE, May 1982, COMPUTE!, July through September 1982, and De Re Atari for more on the GTIA chip, and the GTIA Demonstration Diskette from the Atari Program Exchange (APX). --------------------------------------------------------------------------- Locations 624 to 647 ($270 to $287) are used for game controllers: paddle, joystick and lightpen values.

624 270 PADDL0

The value of paddle 0 (paddles are also called pots, short for potentiometer); PEEK 624 returns a number between zero and 228 ($E4), increasing as the knob is turned counter-clockwise. When used to move a player or cursor (i.e., PLOT PADDLE(0),0), test your screen first. Many sets will not display locations less than 48 ($30) or greater than 208 ($D0), and in many GRAPHICS modes you will get an ERROR 141 -- cursor out of range. Paddles are paired in the controller jacks, so paddle 0 and paddle 1 both use jack one. PADDL registers are shadows for POKEY locations 53760 to 53767 ($D200 to $D207).

625 271 PADDL1

This and the next six bytes are the same as 624, but for the other paddles.

626 272 PADDL2

627 273 PADDL3

628 274 PADDL4

629 275 PADDL5

630 276 PADDL6

631 277 PADDL7

632 278 STICK0

The value of joystick 0. STICK registers are shadow locations for PIA locations 54016 and 54017 ($D300, $D301). There are nine possible decimal values (representing 45 degree incrememts) read by each joystick register (using the STICKn command), depending on the position of the stick: Decimal Binary 14 1110 | | 10 | 6 1010 | 0110 \ |/ \ |/ 11-- 15 ---7 1011-- 1111 --0111 / |\ / |\ 9 | 5 1001 | 0101 | | 13 1101 15 (1111) equals stick in the upright (neutral) position. See Micro, December 1981,for an article on making a proportional joystick. For an example of a machine language joystick driver you can add to your BASIC program, see COMPUTE!, July 1981. One machine language joystick reader is listed below, based on an article in COMPUTE!, August 1981: 1 GOSUB 1000 10 LOOK = STICK(0) 20 X = USR(1764,LOOK): Y = USR(1781, LOOK) 30 ON X GOTO 120, 100, 110 . . . 100 REM YOUR MOVE LEFT ROUTINE HERE 105 GOTO 10 110 REM YOUR MOVE RIGHT ROUTINE HERE 115 GOTO 10 120 ON Y GOTO 150, 130, 140 130 REM YOUR MOVE DOWN ROUTINE HERE 135 GOTO 10 140 REM YOUR MOVE UP ROUTINE HERE 145 GOTO 10 150 REM IF X <> 1 THEN NOTHING DOING. BRANCH TO YOUR OTHER ROUTINES OR TO 155 155 GOTO 10 . . . 1000 FOR LOOP = 1764 TO 1790: READ BY TE: POKE LOOP, BYTE: NEXT LOOP 1010 DATA 104,104,133,213,104,41,12,7 4,74,73,2,24,105,1 1020 DATA 133,212,96,104,104,133,213, 104,41,3,76,237,6 1030 RETURN DOWNLOAD STICK0.BAS See locations 88, 89 ($58, $59) for an example of a USR call using a string instead of a fixed memory location.

633 279 STICK1

This and the next two locations are the same as 632, but for the other joysticks. These four locations are also used to determine if a lightpen (PEN 0 - 3) switch is pressed.

634 27A STICK2

635 27B STICK3

636 27C PTRIG0

Paddle trigger 0. Used to determine if the trigger