Classic Computer Magazine Archive A.N.A.L.O.G. ISSUE 69 / FEBRUARY 1989 / PAGE 16

Master
Memory
Map
Part VII

by Robin Sherer


How to Read the Memory Map

    Beginning users: Read the text that is printed in bold type only. These memory locations will be the easiest for you to use and usually don't involve assembly language.
    Advanced users: Read everything! Many areas of memory are not of any practical use, but you can learn a lot about how a computer works by reading the boring parts.

Page 3

    You probably aren't going to be too thrilled with page 3. Why? It's all about I/O. That means that you may not understand a lot of it, because I/O can get real complicated real fast. Don't worry too much about it, though. BASIC has commands that take care of these locations for you, so you're only reading about these locations for enlightenment. If, on the other hand, you're programming in machine language....
    Before we go any further, make sure you've read at least vaguely on I/O. It's not that long, or complicated, but it will give you a nice overview of what everything here is used for.

Input/Output

    Input/Output, or I/O as it is more commonly called, is an extremely important part of any computer. Without it, the various parts of the computer wouldn't be able to talk to each other. Such communication isn't limited to disk drives and printers, either. The keyboard, television set, and screen editor must all be able to tell the computer what's going on, and all of this is I/O's responsibility. Unfortunately, because I/O has so much to do, it can be a little complicated. Luckily, complicated doesn't mean difficult in this case, so despite all the memory locations that deal with I/O, the basic concept is relatively simple.
    There are three main routines that take care of I/O for a given device ("device" is just a fancy word for the keyboard, printer, or whatever it is we want to talk to). They are shown in Figure A.


Central Input/Output Routine     (CIO)
Device Handler
Serial Input/Output Routine       (SIO)

Figure A. I/O devices

    To help these three routines talk to each other (I told you this got complicated), there are also four "control blocks" in Figure B.

Input/Output Control Block      (IOCB)
Zero-page I/O Control Block (ZIOCB)
Device Control Block                (DCB)
Command Frame Buffer             (CFB)

Figure B. I/O control blocks

    Now that we've got the names straight, let's look at what each does, where it can be found, and how everything is tied together.
    IOCB: Actually, it should be IOCBs since there are eight of them. The IOCBs are found starting at location 832. Each one is made up of 16 bytes that are used to describe what kind of I/O we want to do. Although we can have information in all eight IOCBs at once, we can still only do one I/O operation at a time. IOCBs usually get their information from the user.
    ZIOCB: There is only one ZIOCB, starting at location 32. It is set up exactly like an IOCB, and as a matter of fact contains the information for the IOCB that is currently being used. Why is it necessary? Because page 0 is faster than regular memory, and we want to do I/O as quickly as possible. Since only one IOCB can be used at any one time, it would be a waste of precious page 0 memory to put all eight IOCBs in page 0. CIO transfers the information from the IOCB to the ZIOCB.

    CIO: The CIO routine can be found in the OS ROM, starting at location 58534. CIO takes the information in the IOCB that is currently being used and stores it in the ZIOCB. It then uses that information along with HATABS (794) to figure out which device handler is needed and then passes control to the device handler.

    Device Handler: Again, it should be device handlers, since there is one for each device. The device handlers can be anywhere in memory, with HATABS containing a list of where to find them. A device handler does one of two things. If the device in question is the keyboard, the screen or the screen editor, then the device handler takes care of the I/O itself. If it's something like the disk drive or printer that's plugged into the computer, then the device handler sets up the DCB with the information it needs.
    The exception to this is the disk interface routine, which is also known as the internal disk handler. If you're not using DOS, then you have to set up the DCB yourself in order to talk to the disk drive. If you are using DOS, then a regular disk handler has been loaded into the computer and you can communicate with the disk drive through the IOCBs.

    DCB: The DCB (there is only one) is found starting at location 768. It is 12 bytes long and sort of like the IOCBs in the respect that it holds information that describes what kind of I/O we want to do. This time, however, the information is for SIO instead of CIO.

    SIO: The SIO routines, like the CIO ones, are in the OS ROM, starting at location 59716. SIO takes the information in the DCB and uses it to talk to devices that use serial I/O (printer, disk drive, cassette player, etc.). It also sets up and uses the CFB.

    CFB: Last of all, we have the CFB. Made up of four bytes starting at location 570, it helps SIO talk to the devices. The CFB is the one part of the I/O system that you should not mess around with yourself.
    Let's summarize by looking at the flow of information. The user sets up an IOCB and calls CIO. CIO takes the information in the IOCB, transfers it to the ZIOCB, figures out what device handler is needed and transfers control to that handler. From there, the handler takes care of internal devices, or sets up the DCB and calls SIO if we need to communicate with a serial (external) device. Finally, SIO takes the information in the DCB, sets up the CFB and does the I/O. After the I/O has been completed, whether by the handler or SIO, control is transferred back to the user. As a programmer, you can skip any of these steps with the exception of SIO. You should not skip all the way to the CFB.
    BASIC programmers may want to look at the excellent article in issue 13 of ANALOG Computing for ways to go straight to CIO.

IOCB Command Byte Values

    The third byte in each IOCB is the command byte, called IOCMD. This is the byte that tells CIO what kind of I/O we want to do. It can have the values in Figure 1.

VALUE MEANING
BASIC equivalent
3
OPEN channel OPEN #n
5
GET record INPUT #n
7
GET bytes GET #n
9
PUT record none
11
PUT bytes PUT #n
12
CLOSE channel CLOSE #n
13
GET status none

    Figure 1. IOCB command byte values


    In case you're wondering what happened to PRINT #n, BASIC uses a special vector to talk directly to the handler for this particular statement.
    You should note that with the "GET bytes" and "PUT bytes" routines, BASIC only allows you to GET and PUT one byte at a time.
    If you access CIO directly, however, you can GET or PUT a whole buffer. With this in mind, you may ask what the difference is between GETting or PUTting a buffer and GETting or PUTting a record. If there are no carriage returns (End-Of-Lines or EOLs) in the buffer then there is no difference. A record, however, ends when either the end of the buffer is reached or an EOL encountered.
    CIO takes care of all of these commands. Some of the devices also have their own special commands, which the corresponding device handler takes care of. Here's a list of those commands, which you can access using BASIC's XIO command:

Display Handler

17 DRAW line
18 FILL

Disk File Manager

32 RENAME file
33 DELETE file
35 LOCK file
36 UNLOCK file
37 NOTE
38 POINT
254 FORMAT disk

RS232 Handler

32 Force short block
34 CONTROL DTR, RTS, XMT
36 Configure baud rate
38 Configure translation mode
40 Start concurrent I/O mode

    For more information on any of these commands, you should see the OS manual or the 850 Interface manual.
    If you want to use the resident disk handler (i.e., you're not using DOS or FMS at all), you have to set up the DCB and then do a JSR DISKINV (58451). The DCB has different command values than the IOCB, of course, and a list can be found under DCOMND at location 770.

Back to Page 3

    The first part of page 3 is used for the "device handlers." As the name implies, device handlers are used to handle I/O to the various devices. What devices can we have? The screen (S:), the screen editor (E:), the keyboard (K:), the cassette player (C:), the disk drive (D:), the printer (P:), and the RS232 ports on the 850 interface (R:); all of these handlers, which are just machine language routines, are a part of the OS, with the exception of the RS232 handler. The RS232 handler is stored inside the 850 interface, and gets transferred over to the Atari when you turn on the system.
    Locations 768 through 780 make up the Device Control Block (DCB). To use the DCB you must set it with the appropriate values and then JSR DSKINV (58451) for disk I/O, or JSR SIOV (58457) for other device I/O.

DDEVIC
768     0300

    Three of the devices, S:; E:, and K:, are a part of the computer. The others are all outside the computer, and we therefore need to have some way of talking to them. The "serial bus" takes care of that (the cords you use to connect the devices together are the visible part of the serial bus). But, since you can have more than one device hooked up to the serial bus, you need some way of telling the bus which device you want to talk to. Each device is therefore assigned a number (think of it as a phone number), and the handler gives DDEVIC the number of the device it wants to talk to. Do not change DDEVIC yourself.
    Here are the numbers for the various devices in Figure 2.


Disk Drive 49
($31)
Printer 1 64
($40)
Printer 2 79
($4F)
RS232 Port 80
($50)
Cassette 96
($60)

    Figure 2. DDEVIC chart

DUNIT
769     0301

    We can have up to four disk drives and RS232 ports. DUNIT holds the number of the disk drive, printer or RS232 port we want. DUNIT gets added to DDEVIC, and the result stored in CDEVIC at location 570. CDEVIC is then used during the actual I/O.

If you are using DOS,
then regular disk handler
has been loaded into the
computer an you can
communicate with the
disk drive through the
IOCBS.


DCOMND
770     0302

    Once it has got the number of the device we want to talk to, the handler has to know what it should tell the device to do. For that we have another bunch of numbers, this time for the various commands in Figure 3.


Get Sector 82 ($52)
Put Sector (with verify) 87 ($57)
Put Sector (w/o verify) 80 ($50)
Get Status 83 ($53)
Format Disk
33 ($21)
Download 32 ($20)
Read Address 84 ($54)
Read Spin 81 ($51)
Motor On 85 ($55)
Verify Sector 86 ($56)

Figure 3. DCOMND chart

    This is one of those tables that gives you the confidence that you know what's going on, until you get about halfway down. The first five commands are probably the only ones you'll ever run into, so don't worry too much about it.
    DDEVIC gets transferred over to CDEVIC (570) for use by SIO.

DSTATS
771     0303

    Two uses for DSTATS. First of all, after an I/O operation is complete, it holds the status of the operation. A zero means that everything went OK. See the OS manual for the meaning of non-zero values.
    Before the I/O operation, DSTATS tells SID how data is going to be transferred, using bits six and seven as in Figure 4.

00------ ($00) means no data will be transferred in this operation.
01------ ($40) means data is going to be read from the device.
10------ ($80) means data is going to be written to the device.
11------  ($00) is not a valid combination.

Figure 4. DSTATS chart

DBUFLO, DBUFHI
772,773     0304,0305

    This is a pointer to the buffer that will be used to store the data that is to be sent or received during I/O(!). It's set by the handler to the system buffer at CASBUF (1021) unless you tell the handler differently.
    If a GET STATUS command is given, then DBUFLO/HI is set to point to DVSTAT (746).
    If you're communicating with SIO directly, you should make sure you set DBUFLO/HI yourself.

DTIMLO
774     0306

    DTIMLO is the time-out value for the device being used and is set by the handler. You will recall from our other run-ins with time-outs that a value of 60 here represents 64 seconds.
    DTIMLO is initialized to 31.

DUNUSE
775     0307

    Another unused byte (warning, warning!).

DBYTLO, DBYTHI
776,777        0308, 0309

    This location specifies the number of data bytes that are to be read to, or written from, the buffer during I/O. It is also used by the FORMAT command to store the number of bad sectors.
    The values in DBUFLO/HI and DBYTLO/Hl are added together after the I/O is over, and the results stored in BFENLO/HI (52,53).
    Just in case you thought the OS was perfect, there's a bug that messes things up if the last byte in the buffer is in an address that ends in $FF (such as $41FF, $32FF, etc). Be careful about this.

DAUX1, DAUX2
778,779     030A,030B

    These are used to provide information that is unique to the specific device (a sector number, for example). Their values are transferred to CAUX1 and CAUX2 at locations 572 and 573.
    The next 14 locations (780 to 793) have various SIO uses.

TIMER1
780,781        030C, 030D

    TIMER1 is the initial timer value for the baud rate. What does that mean? Back at CBAULDL/H (750, 751) we discovered what a baud rate is and how the OS constantly adjusts it during I/O. We found out that an alternating bit pattern is read and timed in order to figure out the correct rate. TIMER1 stores the time at the beginning of this pattern, and TIMER2 below stores the time at the end of it. The difference in these times is then used to figure out the new baud rate.
    The first byte of both TIMER1 and TIMER2 is the value of VCOUNT (54283) at the time, and the second is the value of RTCLOK+2 (20).

ADDCOR
782     030E

    ADDCOR is an "addition-correction flag" used in the baud-rate calculations. Those quotation marks mean that you'll never need to know what it means.

CASFLG
783     030F

    Part of the SIO routine is not needed for cassette I/O, so CASFLG is used to warn SIO that cassette I/O is being done. A value of zero means regular SIO, 255 means cassette.

TIMER2
784,785        0310, 0311

    This is the final timer value for baud-rate. See TIMER1 for a complete description.

TEMP1
786,787        0312, 0313

    TEMP1 is used as a temporary storage location for the difference in the TIMER1/2 values during the baud-rate calculation.

TEMP2
788     0314

    Supposedly another temporary storage location of some sort, but according to the OS listing it isn't used.

TEMP3
789     0315

    Another temporary storage location that is used, but for nothing particularly important.

SAVIO
790     0316

    Back to setting the baud rate. Remember the alternating bit pattern (see TIMER1 if not)? SAVIO is used to check the serial port SKSTAT (53775) to see if the next bit has come in yet. That's all.

TIMFLG
791     0317

    This is a flag to indicate that the cassette player has timed out (taken a snooze). If it's equal to one, we're OK. If it's equal to zero, then we're in time-out territory.
    For the cassette player to time-out, a data byte must not be found within the given time period (which can vary). This usually indicates that the baud rate was wrong, assuming that you remembered to connect the cassette player, plug it in, put in the program tape and press "Play"!

STACKP
792     0318

    Remember the stack at page 1? When SIO first gets going, it stores the value of the stack pointer in STACKP. That way, if somebody presses BREAK before it's done, it can restore the stack pointer and return to where it was called from.

TSTAT
793     0319

    This is used to temporarily hold the value of STATUS (48) during I/O.

HATABS
794-831     031A-033F

    We now know a little about what handlers do, but where do we find them? Obviously HATABS is going to have something to do with it, but before I tell you what, let's talk a little more about handlers.
    Each handler is made up of a bunch of routines that perform different I/O functions. These functions are shown in Figure 5.

OPEN device
CLOSE device
GET BYTE from device
PUT BYTE to device
GET STATUS of device
SPECIAL
INITIALIZE device

Figure 5. I/O functions chart

    Since SIO is going to need to know where each of these routines is, it's useful to keep the address of each routine in a table. We'll only need the initialization routine once, so we'll put a JMP instruction in the table right before the initialization address. Finally, we'll call this table the "handler entry point" table, which makes sense if you think about it.
    Okay, so now we have a handler entry point table for each of our handlers. Now we need a table of the addresses of these tables (aren't computers fun?). This is where HATABS comes in. Each entry in HATABS consists of the ATASCII value of the one character device name ("C", "D", "K", etc.), followed by the address for the handler entry point table for that device. So, keep in mind that even though HATABS is called the "handler address table," it is actually the handler entry point table address table!
    When you first turn on the computer, five entries are automatically set up in HATABS. They are for the printer, cassette player, screen editor, screen and keyboard handlers, in that order. If a disk drive is hooked up and turned on, then the entry for the disk handler is added. Finally, if the 850 Interface is hooked up and on, the entry for the RS-232 handler is added after that for the disk. The addresses for the handler address table of each of these are shown in Figure 6.

"P"            58416
"C"           58432
"E"            58368
"S"            58384
"K"           58400

"D"           1995
"R"           varies

Figure 6. Addresses for handler address table

    The address for "R" varies depending on whether you have a disk drive hooked up and, if so, what kind of DOS you are using. PRINT PEEK(813)+256*PEEK(814) will give you the address for your particular setup.
    You can use the preceding addresses to take a look at the handler entry point tables. The addresses in these tables are in the same order that the routines were listed (OPEN, CLOSE, etc.). Don't forget that each address is two bytes long with the exception of the last one, which includes a JMP instruction (76).
    HATABS is 38 bytes long, which means there is room for 12 three-byte entries (the last two bytes are set to zero and ignored). Even if you are using the disk and RS-232 handlers, that still leaves five entries free. These entries are initially set to zeros, but they're free for your use if you want to write your own handler.
    Since the task of writing your own handler is one that most people won't really get into, I'm not going to go into any more detail on it here. If you're interested, De Re Atari and the OS manual should provide all the information you need.
    One more thing you'll need to know. CIO searches for a handler address from the end of the table up to the beginning. This means that if you write your own screen handler, for example, CIO will use it instead of the original one.

Input/Output Control Blocks (IOCBs)

    Back at locations 32 through 47, we ran across something called the Zero-page Input/Output Control Block (ZIOCB). The ZIOCB gets its values from one of the eight Input/Output Control Blocks (IOCBs) located at locations 832 through 959. Basically, the IOCBs are nothing more than a bundle of information used to communicate between the user and the handlers, BASIC usually takes care of them for you in commands like OPEN, PLOT, LPRINT, and so on (all the BASIC I/O commands).
    Each IOCB is 16 bytes long, and those bytes are named and used as follows:

ICHID (one byte): This is an offset into HATABS (794 through 831) that points to the name of the device that the IOCB is OPENed for. For example, try the following:


100 IOCB1=848:HATABS=794
110 OPEN #1,4,0,"K:"
120 INDEX=PEEK(IOCB1)
130 PRINT "You just OPENe
d device ";CHR$(PEEK(HATA
BS+INDEX));":"

    ICHID is set by the OS.

    ICDNO (one byte): This is the device number. One for Dl, two for R2, etc. It is also set by the OS.

    ICCOM (one byte): This is the command that specifies what kind of I/O operation we are going to be doing. It is set by the user.

    ICSTA (one byte): This is the status of the last I/O operation.

    ICBAL/H (two bytes): This is either the address of the data buffer, or the address of the user's filename (depending on the command).

    ICPTL/H (two bytes): This is the address minus one of the put-one-byte routine for the device being used. If the IOCB isn't OPEN, then it points to CIO's error routine for an illegal put.

    ICBLL/H (two bytes): This is the number of bytes that still have to be transferred. Note that under some circumstances not all bytes will be transferred.

    ICAX1 (one byte): This is an auxiliary byte (and is also called AUXI), meaning that it helps out ICCOM in specifying what is to be done. It is usually used to modify the OPEN command, but you can use it for your own handlers. With the OPEN command, it is the first value after the IOCB number (#n is the IOCB number), with the bit meanings in Figure 7.

-------1 (1) append
------1- (2) directory
-----1-- (4) read
----1--- (8) write
--1----- (32)
OPEN screen without erasing screen memory

Figure 7. ICAX1 bit meanings

    Some combinations are not allowed on some devices. For example, OPEN#1,12,0, "D:TEST" would open a disk file called TEST, and let you read and write to that file. This wouldn't work on a cassette file though.

    ICAX2 (one byte): This is the second auxiliary byte, and is also called AUX2. There is no common use for this or any of the other auxiliary bytes; their use depends on the handler. For example, if AUX2 is equal to 128, the cassette handler will put shorter gaps between the records on the tape when it writes data.

    ICAX3/4 (two bytes): These auxiliary bytes are used by BASIC's NOTE and POINT commands to keep track of the sector number. They are not also called AUX3 and AUX4.

    ICAX5 (one byte): This is the fifth auxiliary byte and is also used by NOTE and POINT as the number of the byte within the sector.

    ICAX6 (one byte): Okay, enough of the "this is" garbage. I won't even insult your intelligence by telling you it's the sixth auxiliary byte. It has no specific use.

    You can use the IOCBs directly by POKEing the values you want into them and then doing a JSR SIOV (58454). See SIOV for more details.
    Note that the descriptions for the ZIOCB (32-47) are worded differently from the preceding descriptions, so be sure to read them as well for a better understanding.

IOCB0
832-847 0340-034F

    This is, obviously, IOCB zero. If you're using the screen editor, then don't use IOCB0; that's what the screen editor uses. If you are using the screen editor though, you can do neat things by telling the IOCB to send the data somewhere else, like the printer. Try this if you have a printer:

100 GRAPHICS 0
110 PRINT "Now we're on t
he screen"
120 POKE 838,166:POKE 833
,238
130 PRINT "Now we're on t
he printer"
140 POKE 838,163:POKE 839
,246
150 PRINT "Now we're back
 on the screen"

    What we're doing here is changing ICPTL/H to point to the printer's put-one-byte routine rather than the screen editor's. Note that this doesn't turn your computer into a typewriter. The screen editor isn't responsible for putting characters you type on the screen; it only works for things the computer prints on the screen.
    Another neat thing you can do to the screen editor is give AUX1(842) a value of 13. This tells it to "append," which doesn't really make any sense. What it does, though, is act as though you were continually pressing the Return key. This lets you write a program that will change itself. You simply print some program instructions on the screen, position the cursor on the line of the first instruction, and POKE 842 with 13 to start the computer generating Returns, which reads in each line. When the computer POKES 842 with a 12, the process stops and everything is back to normal. While you do this, the lines of code will appear on the screen, but you can make them invisible by setting the color of the letters to the color of the screen. Try this:

10 ? CHR$(125):LIST 30
20 FOR I=1 TO 1000:NEXT I
30 ? " THIS IS LINE 30"
40 FOR I=1 TO 1000:NEXT I
50 ? CHR$(125)
60 POSITION 2,18:? "  30
?";CHR$(34);" NOW LINE 30
 SAYS SOMETHING ELSE"
70 POSITION 8,2
80 POKE 842,13
90 POSITION 2,17:? "CONT"
100 POSITION 0,2:STOP
110 POKE 842,12
120 ? CHR$(125):? "NOW LE
T'S SEE WHAT LINE 30 SAYS
"
130 ? "THE PROGRAM MODIFI
ED ITSELF!"
140 LIST 30


    Keep in mind that if you try and delete the lines that change location 842, you'll confuse the heck out of the computer and it will just keep on "pressing" Return forever!
    The screen editor, and therefore IOCB zero, is used in graphics mode 0 and in other graphics modes that use text windows. Since IOCB zero is dedicated to the screen editor, however, you should stay away from it even if you're not using the text editor.
    IOCB zero is not closed by a NEW, RUN or LOAD command. All the others are.

IOCB1
848-863     0350-035F

    IOCB one.

IOCB2
864-879     0360-036F

    IOCB two.

IOCB3
880-895     0370-037F

    IOCB three.

IOCB4;
896-911     0380-038F

    IOCB four.

IOCB5
912-927     0390-039F;

    IOCB five.

IOCB6
928-943     03A0-03AF

    IOCB six. If you're in a mode other than zero, then IOCB six is used for the screen (IOCB is used for the text window).

IOCB7
944-959     03B0-03BF

    IOCB seven is used by BASIC for I/O to the printer, disk drive and cassette. That means that this is a pointer to the buffer that will be used to store the data that is to be sent or received during I/O (!). It's set by the handler to the system buffer at CASBUF (1021) unless you tell the handler differently.
    If a GET STATUS command is given, then DBUFLPO/HI is set to point to DVSTAT (746).
    If you're communicating with SIO directly, you should make sure you set DBUFLO/HI yourself.

PRNBUF
960-999     03C0-03E7

    This is the print buffer, 40 bytes long, used in sending data to a printer. See PBPNT (29; $001D) and PBUFSZ (30; $001E) for details on how this works.

    Forty bytes, as you may be aware, is somewhat shorter than most printer lines (most have 80 character lines). The OS can usually handle this, but sometimes it runs into problems. Semi-colons and commas at the end of LPRINT statements especially tend to mess it up. Several sources briefly mention that the Atari can deal with an 80 column printer if you call it "P2. " If this is true, then you have to OPEN a special IOCB for it and therefore couldn't use LPRINT (you'd have to use PUT and the likes). You're probably better off just to put up with the quirks.

Noname
1000-1020     03E8-03FC

    These bytes are marked as being spare, but again, be careful about using them.

CASBUF
1021-1151     03FD-047F

    This is the cassette buffer, which is where the cassette handler reads and writes data from and to. It's also used to hold the first disk record when a disk is booted (the OS doesn't know where to put the disk file in memory until it gets a chance to look at this record; see BOOTAD [578,579]).
    A cassette record is made up of 132 bytes. Only 128 of these are actual data; the other four help out the cassette handler. How? I'm glad you asked. The first two bytes, as we learned at CBAUDL/H (750, 751), are used to help the handler figure out the correct baud rate. The third byte tells the handler how much data is in the file. It can have the following values:
    A value of 250 means that there are less than 128 bytes of meaningful data (there will still be 128 bytes, but some of them toward the end will be zeros). The 128th data byte will give the actual number of meaningful bytes.
    A value of 252 means that all 128 bytes are important.
    A value of 254 means that this is the last record in the file and all 128 bytes will be equal to zero.
    The next 128 bytes are the actual data. Notice that they will be stored in CASBUF starting at 1024 and ending at 1151.
    But wait, that was only 131 bytes and you said there were 132. Where does the 132nd go if we already filled the buffer? The last byte in a cassette record is the checksum, which is used to make sure that the rest of the data was read correctly. It gets stored at CHKSUM (49), and you should take a look at CHKSUM for a more detailed description of how a checksum works.
    Take a look at BPTR (61) and BLIM (650) for more information on the way the buffer is used.

    Locations 1152 through 1791 are not used by the OS. Most of them are, however, used by BASIC and/or the floating point package. Only the locations in page 6 (1536 to 1791) are not used by either. See page 6 for more information.

SYNSTK
1152-1405     0480-057D

    This is BASIC's syntax stack. Unfortunately, since there doesn't seem to be any information on what it's for, I can't explain it to you (I never claimed to be perfect). I suspect, however, that it's used during the tokenization of the BASIC program, since BASIC has the runtime stack (see RUNSTK [142,143]) to use when the program is actually running.

LBPR1
1406     057E

    LBUFF prefix 1. Again, no information on this one.

LBPR2

1407     057F

    LBUFF prefix 2, also not explained anywhere.

LBUFF
1408-1535     0580-05FF

    Before I go on, a few words on locations like these. Atari was very nice in releasing the OS listing; a lot of other computer companies don't. Atari did not, however, because of legal restrictions, extend that niceness to BASIC and the floating point package. Therefore, locations that are used by these two are very difficult to explain. The useful locations have been documented, so they can be understood and used by yourself. Ones like these, however, are somewhat obscure, so that you should never have to use them. In other words, don't feel that you're not getting something you'll need.
    Now that I've freed myself from the responsibility of properly explaining these locations, I'll actually give you some information on this one. This is a buffer used in converting floating point values to ATASCII values. It's pointed to by INBUFF at locations 243 and 244. Now INBUFF supposedly points to the buffer used to convert ATASCII to floating point, so I suspect that LBUFF swings both ways.
    LBUFF is also referred to as the "input line buffer," which implies that this is where a BASIC line is stored when you first type it in.
    Location 1535 is the last byte in the buffer and so it is also called LBFEND. Notice that the next three locations are all within LBUFF.

PLYARG
1504-1509     05E0-05E5

    Polynomial arguments. Sure!

FPSCR
1510-1515     05E6-05EB

    This is like a work area for the floating point package.

FPSCR1
1516-1535     05EC-05FF

    The same, only bigger.

Page 6

    Locations 1536 through 1791 are normally not used by the OS, BASIC or the floating point package. That leaves them free for your use. (Page 6 is a good place to store a machine language routine.) Now I did say that they are "normally" not used. That means that they're not completely safe. If you try and INPUT more than 128 bytes during I/O, then the extra bytes are stored in page 6. That means one of two things. Either don't INPUT more than 128 bytes at a time, or only use the second half of page 6 (locations 1664 through 1791). These locations are absolutely guaranteed not to be used by anything no matter what.
    Please notice that I only said the OS, BASIC and the floating point package wouldn't use page 6. If you are using another language, it might, so check the documentation that comes with it.

Page 7,8,9....

    If you're not using a disk drive, then location 1792 is the beginning of free memory. If you're using BASIC, "free memory" doesn't mean memory for you to use; it means memory for BASIC to use. There's a difference between the two, and you should go back to locations 128 through 145 if you don't know what it is.
    If you are using a disk drive, then the locations from 1792 to the address stored in MEMLO (743, 744) are used by DOS and the File Management System (FMS). The value of MEMLO will depend on the version of DOS that you're using, and also on a couple of other things that will be mentioned next. Use PRINT PEEK (743) +PEEK(744)*256 to find out the value for your particular setup.
    This column is designed to teach you about your Atari and not about DOS, so I'm not going to go into any detail about how DOS works or what the locations are for. If you're interested in DOS, take a look at COMPUTE's book Inside Atari DOS.

Free RAM

    The memory area from the address pointed to by MEMRO (743, 744) up to that pointed to by RAMTOP (106) is free RAM. That doesn't mean you didn't pay for it; it means that it is unused. If you are using BASIC, then your program uses the memory from the address pointed to by MEMLO up to the address pointed to by MEMTOP (144,145).
    As mentioned already, the value of MEMLO will depend on whether or not you are using disk (and the RS-232 handler, which takes up another 1728 bytes). The value in RAMTOP depends on how much total memory you have. The various values it can have are listed in Figure 8. Don't forget that the value in RAMTOP is the high byte of the address (the number of pages).

MEMORY RAMTOP BYTES
  8K
  32
  8192
16K
  64
16384
24K
  96
24576
32K
128
32768
40K
160
40960*
48K
192
49152*

Figure 8. RAMTOP chart

    *These values depend on whether or not any cartridges are in place. See the sections on cartridges.

Cartridge B (right cartridge)

    The cartridges are a strange breed. They contain their own 8K of ROM, yet they feel the need to shove 8K of RAM out of the way in order to run. The right cartridge gives notice to locations 32768 through 40959 ($8000 through $9FFF). This means that if you have 40K of RAM or more, you'll lose 8K of it. Note that since the 800 is the only Atari that has a right cartridge slot, few companies have cartridges for the slot.
    If a right cartridge is present, TRAMSZ at location 6 gets set to one during powerup.

Cartridge A (left cartridge)

    Okay, all Atari computers have a left cartridge slot. Since it may be the only slot, it makes more sense to refer to it as cartridge A.
    Cartridge A takes up memory locations 40960 through 49151 ($A000 through $BFFF). This will only affect you if you have 48K of RAM, since these locations are the last 8K.
    The last six bytes in a cartridge provide the information that the OS needs in order to run the cartridge. Thus:

    49146, 49147 ($BFFA, $BFFB) holds the starting (run) address of the cartridge.

    49148 ($BFFC) equals zero if a cartridge is plugged in, and doesn't if one isn't.

    49149 ($BFFD) tells the OS how to get the cartridge going. If bit 0 is set, then the OS boots the disk before it runs the cartridge. If bit 2 is set, then the cartridge is initialized but not run (if it's not set then it gets run).

    49150, 49151 ($BFFE, $BFFF) holds the initialization address of the cartridge.

    Note that these addresses are all for cartridge A. For cartridge B, just subtract 8192 from each address.
    If cartridge A is present, TSTDAT at location 7 gets set to one during powerup.
    If you're using BASIC, then BASIC is' cartridge A. Because this book is designed to teach you about your Atari, and not about the languages that can be used with it, I'm not going to give you a detailed listing of all the locations in BASIC. Don't feel as though you're missing out on something great, however; there's very little in there that would be useful to you. The OS listing does mention four routines, however, so I will mention those.

SIN
48551     BDA7

    This routine calculates the sine of the number in floating point register zero (FR0). You should take a look at FR0 (212 to 217) and RADFLG (251) if you're going to try to use it. It might also help to disassemble the code for the routine to get an idea of what's going on.

COS
48561     BDB1

    This routine calculates the cosine of FR0.

ATAN
48759     BE77

    The arctangent of FR0.

SQR
48869     BEE5
    And lastly, the square root of FR0. Note that the carry is significant in all of these operations, in that it will be set if an error occurs during the operation.