Using The Atari Forced Read Mode
Frank C. Jones
Automatic data entry, line numbering, deletion, self-modifying programs – this programming method opens up a new level of control over the computer's behavior during a RUN.
There are many occasions when it would be useful if one could cause data and program lines to be entered into the computer's memory without having to push the RETURN key. Such a facility could be used to enable a program to alter itself by adding or deleting program lines or to automatically reenter data that had been temporarily stored on the screen. In the article "Restoring and Updating Data on the Atari" (COMPUTE! August, 1981, #15) Bruce Frumker has shown that the Atari computer does indeed have this capability. In this article we will explore this facet of the Atari a little further with an eye to gaining a better understanding of how it works, and give a few examples of how it can be put to good use.
To begin our exploration we must visit those often mentioned, but little understood, objects – the IOCB's. IOCB stands for Input/Output Control Block. There are eight of them, and each one is nothing more than sixteen contiguous bytes of RAM. IOCB #0 runs from $340 to $34F (Dec. 832 to 847), IOCB #1 runs from $350 to $35F (Dec. 848 to 863), and so on.
Most input and output is handled by a portion of the Atari Operating System called the CIO (Central Input/Output) facility. When the CIO is called by the program that is ready to do some I/O, only one number is passed to it, the number of the IOCB that is to control the actual I/O operation. All of the other information that the CIO needs (to perform the required I/O operation for you purists) is contained in the sixteen bytes of the IOCB in question. Of course, all of the required information must have been placed in the proper bytes of the IOCB prior to the jump to the CIO entry point. One of the ways that such information is placed in the IOCB is with the OPEN statement in BASIC. However, we are getting a bit ahead of ourselves; we will return to the OPEN statement shortly.
A few examples of the sort of information that the CIO will find in the IOCB are : the first byte contains the ID number of the device that is to exchange data with the computer, the third byte contains the code that tells CIO what it is supposed to do (read data, write data, etc.), the fifth and sixth bytes contain the address of the data to be output or the location where incoming data is to be stored, and so on until the eleventh byte (the auxiliary information byte or ICAXl).
Here is where we return to the OPEN statement of BASIC.
When a BASIC program executes a statement such as OPEN #2, 8, 0, "P", IOCB #2 is set up to write data to the printer. The number 8 in the command means "write data." What many do not know is that the OPEN command sends that number 8 to the eleventh byte of IOCB #2 or, in other words, ICAXl. The number 8 is represented by the 3 bit of ICAXl being set. This tells CIO that the channel has been set up for output. If the 2 bit were set, that should represent number 4 and would mean that the channel was set up for input. If both bits are set (a number 12, output and input are both enabled.
We can see now why the 2 and 3 bits of ICAXl are called "direction bits" – they control the direction of data flow. However, this is not all that the bits of ICAXl can do. Certain I/O devices can be made to do special things by setting some of the other bits. The Screen Editor is one of these certain devices. It supports a mode of operation that Atari calls the force read mode. It would seem to me that "forced enter mode" is a more descriptive name, but I suppose that this sounds too much like "forced entry" and hence, a bit too felonious. This mode is enabled by setting the zero bit of ICAXl in any IOCB that is OPENed to the Screen Editor. Setting the zero bit is, of course, accomplished by adding one to the number that the OPEN command sends to ICAXl.
This means that a command such as OPEN #2, 5, 0, "E" or OPEN #2, 13, 0, "E" would set up channel number 2 to the Screen Editor in the forced read mode. Note that OPEN #2, 9, 0, "E" is not appropriate since it doesn't make much sense to invoke the forced read mode in a channel that has been set up for output only.
The obvious question that now comes to mind is : What is the forced read mode? The answer is simple. Whenever an INPUT command is issued over a channel (IOCB) that has been set up for forced read, the Operating System does not wait for the operator to push the RETURN key, but immediately INPUTs the data from the logical line in which the cursor is residing. All data that is under or to the right of the cursor may be INPUT at this time. Note carefully this last remark. This mode does not work precisely like the more usual one in which data to the left of the cursor may be INPUT.
As an example of the utility of this mode we will now write the world's simplest text screen dump. Early in the program the forced read mode should be set up with a program line such as:
0 OPEN #2, 5, 0, "E" : DIM LINE$(120) : SDUMP = 32000
Since OPENing an IOCB to the screen editor clears the screen, this line should be executed before anything is written to the screen that you might want to dump to the printer. LINE$ is the string that will hold a line of text from the screen and SDUMP is the line number of the beginning of the dump routine. It can be called from anywhere in your program or from the immediate mode by the command GOSUB SDUMP. The dump routine is as follows:
32000 POSITION PEEK(82), 0 32010 FOR I = 1 TO 24 32020 INPUT #2, LINE$ : LPRINT LINE$ 32030 NEXT I : RETURN
What could be simpler? Of course, this won't format the text on the printer exactly as it appears on the screen, and it might cause some scrolling if you have some logical lines that are longer than one physical line, but it will dump all of the text on the screen to the printed page.
There are many other cases in which it is advantageous to be able to read data from the screen automatically. One occurred to me as I was trying to work around what seemed at the time to be an insurmountable problem. I was working on a program that was to read tape files and perform calculations on each file before going on to the next one. A fairly large array was needed whose size depended on the data in each file. I could DIMension the array to the largest size that I would ever need, but that would be wasteful of memory. Besides, I wasn't sure that I could ever guess just how large that would be. An alternative would be to use the CLR command and reDIMension the array after reading each data file.
The trouble with that is that I wanted to maintain a running total from one file to the next and the CLR command would clear all variables. While pondering this dilemma, I decided that I could write the current value of the running total on the screen, use the CLR command, and then read it right back again using the forced read mode. Of course, if you have a disk system all of this is unnecessary; you can use a disk file as temporary storage. But if (like me) you have only cassette storage, this kind of file manipulation is not possible. It is nice that folks like us do have the alternative of the forced read mode.
This method is by no means limited to storing only one value; you can print several numbers, separated by commas with a command like PRINT A; ","; B; ","; C; – etc. and then read them back in with a multiple variable INPUT statement. If you have reasons for not wanting all of this screen activity to be seen, you can make the writing and background the same color, as Bruce Frumker did. Or you can disable screen DMA with a POKE 559, 0, then do your thing with the screen. When you are done, clear it, and restore DMA with a POKE 559, 34. I am still thinking of variations on this technique, and I am sure that you will think of many that have not occurred to me.
So far none of this allows a BASIC program to modify itself in any way, although Bruce Frumker's mysterious POKE 842, 13 should be taking on a familiar look. A little calculation will show you that location 842 is the ICAX1 byte of IOCB #0, the one IOCB that BASIC won't let you OPEN, CLOSE or otherwise modify. The reason that BASIC won't touch IOCB #0, is that it is reserved for the Operating System to use in communicating with the screen editor. Whenever a BASIC command such as PRINT, ?, LIST, or INPUT that does not specify a particular IOCB is executed, the Operating System uses IOCB #0 to do the job. In fact, any time you use the screen editor to communicate with the Atari, such as entering immediate mode commands, entering or deleting program lines or anything, you do it through IOCB #0.
Even when it may look as if nothing at all is going on with your Atari, the Operating System is actually issuing repeated INPUT (or its equivalent) commands through IOCB #0 to the screen editor. It is just waiting for you to print something on the screen and then press RETURN. Of course, if IOCB #0 were in the forced read mode it wouldn't wait for you to press RETURN, would it? The idea is getting closer (although I'll bet that a lot of you are already there).
Although the general rule exists that once ICAX1 has been set by an OPEN command it shouldn't be changed, it turns out that turning the forced read mode on and off is an exception and the statements POKE 842, 13 and POKE 842, 12 do just that. Once IOCB #0 has been placed in the forced read mode and the BASIC program relinquishes control to the Operating System (with a STOP or END statement), the Operating System starts immediately scanning the screen for program lines to add or delete or immediate mode commands to carry out. This will continue until it comes across a command that returns control to the BASIC program (CONT RUN, or GOTO line#) or turns off the forced read mode (POKE 842, 12).
Although this may sound very straightforward, it takes some careful planning to position the cursor and the printed lines to make sure that the desired lines are, in fact, read when the Operating System takes over. A few things need to be remembered:
- First, when a program line (including a blank line) is read, the cursor jumps to the beginning of the next logical line to INPUT the next line. So far, so good.
- When a BASIC program comes to a STOP statement, the cursor skips a line, prints "STOPPED ON LINE line#," and is ready to read on the line following that. In other words, you must position the cursor two lines above the line where you wish to start reading. (Using END to stop the program does the same thing, only READY is printed instead.)
- When an immediate mode command is read, the cursor skips a line, prints READY and starts reading again on the line following that; i.e., two lines are skipped.
If the lines to be read are not positioned with these facts in mind, some of the lines may be missed and not read. This can be especially annoying when the line that is missed is the one that turns control back to the BASIC program or turns off the forced read mode. In this case the cursor "runs away" and continues to look for lines to read until something stops it. There is no need to panic, however. The SYSTEM RESET key will bring everything back to normal.
A little practice is all that it takes to get the hang of setting up the screen to be read. If you find that some of your lines are not being read or the cursor is running away, look for something that is making the cursor skip a line or two that you had not counted on.
Uses for this mode abound. Have you ever wondered how an algebraic formula could be entered into a program at run time and become incorporated in the program to be evaluated and plotted? The forced read mode is the answer. In fact, Atari programmers have used just this technique in the GRAPH IT programs. A program that initially POKEs a long machine language subroutine into memory when it is first RUN can eliminate this POKEing routine when it is through with it. In this way, it can avoid this time consuming and unnecessary process when it is reRUN.
The automatic generation of DATA statements as in Bruce Frumker's program is a natural use of the forced read mode. However, there is one case where it is almost a necessity to remove this function from error prone human hands. Anyone that has used the Atari Editor/Assembler cartridge to write a machine language subroutine has had to face the rather tedious job of incorporating it into the BASIC program that is to use it. This job is not only difficult, but is a very likely source of errors as it is very hard to type a meaningless string of numbers without making at least one mistake, and machine language is not at all forgiving of the smallest mistake.
Getting the program in memory in the first place is not too difficult using the short BASIC program supplied with the Editor/Assembler manual errata sheet. The real problem comes when one wants to integrate it into the BASIC program. Program I should be a help in this respect. It reads the binary file generated by the Editor/Assembler SAVE command and generates the appropriate DATA statements for subsequent POKEing into memory.
In the program you will see a couple of words in curly brackets. They represent screen control characters. They are printed by pressing the ESC key and the appropriate control key. (CLEAR) is the screen clear character, and (BACK) is the DELETE BACKSPACE key. Now for the program description.
Line 5 – Get ready for the EOF record
Line 10 – This is written for cassette files; the generalization to any kind of file is obvious
Lines 20-40 – The first six bytes of a binary file contain the location in RAM of the program; it is assumed that the BASIC program will POKE it into the correct location
Line 50 – The J's are the DATA statement line numbers; they may be changed at your convenience (except › 460). Be sure to have enough.
Line 70 – The range of I has been chosen to put twenty-five numbers in each DATA statement. This, too, can be changed, but you must make sure not to exceed a logical line length
Line 95 – Erases the last comma
Line 100 – Prints the command to return control to the program
Line 110 – Positions the cursor, turns on the forced read mode, and turns control over to the Operating System
Line 120 – Turns off the forced read mode
Line 300 – Checks the error number and if it is an EOF, lines 400-430 set up the last DATA statement and enter it into memory
Lines 440-450 – Clear the screen and LIST the data statements
When this program has finished its job, the DATA statements can be listed to a file for later inclusion in a BASIC program. It should be easy to modify this program to your own needs. The basic framework is there, and now that you understand how it works, write one that fits your programming style more closely.
I am sure that these uses of the forced read mode are only the first hints of what will become an entirely new dimension in Atari programming. I am eager to see what will come next.
PROGRAM. Using The Atari Forced Read Mode.
5 TRAP 300 10 OPEN #1, 4, 0, "C" 20 FOR I = 1 TO 6 30 GET #1, A 40 NEXT I 50 FOR J = 500 TO 5000 STEP 10 55 PRINT "{CLEAR}" 60 POSITION PEEK(82), 2 : PRINT : PRINT J; " DATA "; 70 FOR I = 1 TO 25 80 GET #1, A : PRINT A; ","; 90 NEXT I 95 PRINT "{BACK S}" 100 PRINT "CONT" 110 POSITION PEEK(82), 0 : POKE 842, 13 : STOP 120 POKE 842, 12 130 NEXT J 300 IF PEEK(195) = 136 THEN 400 310 PRINT " ERROR - "; PEEK(195) : END 400 PRINT "{BACK S}" 410 PRINT "CONT" 420 POSITION PEEK(82), 0 : POKE 842, 13 : STOP 430 POKE 842, 12 440 PRINT "{CLEAR}" 450 LIST 500, 5000 460 END
Return to Table of Contents | Previous Section | Next Section