By Charles Bachand
One piece of software that has come my way is an Assembler/Editor program by Optimized Systems Software (OSS) called EASMD. This is a disk based program that is remarkably similar to ATARI's cartridge Assembler. And well it should be, for it was written by the same people who wrote the ATARI Assembler. Now, since this version is resident in RAM, the programmers were not limited to the space restraints of a ROM cartridge. They had plenty of space left for those little extras such as long error messages, a symbol table at the end of an assembler listing, verification of a line after changing characters using the command REP, and the feature that makes me pick it over the cartridge: the directive .INCLUDE #filename.
You might have guessed that programmers who do a lot of work with an Assembler (like maybe 4K of object code is a lot, eh!), tend to have very large source code files. So much source code in fact, it will not all fit into the available RAM space (even with 48K). This is where the INCLUDE directive of OSS's EASMD comes into play. Instead of one big file of source code, the program is written as a bunch of little files. As an example, we will call these files "D:FILE1", "D:FILE2", and "D:FILE3". These will be my source files. We now make one last file, which contains the following statements:
0100 .INCLUDE
0100 INCLUDE #D:FILE1
0110 INCLUDE #D:FILE2
0120 INCLUDE #D:FILE3
When these statements are executed, OSS's EASMD will open FILE I, read the source code, close FILE 1, open FILE2, read that source code, etc., etc.
INCLUDE directives are not necessarily limited to a separate file. They may be included within the text of a program. An example of this would be the inclusion of often used subroutines in one's programs. Many of my own machine language programs make extensive use of joysticks and the START, SELECT, and OPTION switches. Since the code to access these devices was written to be the same in all cases, it is to my advantage to have the Assembler INCLUDE the code while it is in the process of assembling. This cuts down not only on typing, but also your disk space usage. The INCLUDE feature is an absolute necessity when your lines of source code start to number in the thousands.
Getting back to some resemblance of a tutorial, I would like to tell you a little about binary load files and a curious problem I encountered. This problem, it turns out, was with my understanding of binary loaded files at the time. But first, what the @&%"?# is a binary load file?
As you may have noticed, the menu for Atari's Disk Operating Systems, DOS for short, come onto your television screen, there are two options displayed which are rarely used by many casual users. These are (L) Binary Load, and (M) Run at Address. The first loads a binary file into RAM and the second specifies the address to start executing a machine language program at.
A binary file is organized in such a way that a program, such as DOS, will be able to load it into memory. The format that was finally decided upon, and which is used by both DOS 11 and the Assembler/Editor Cartridge is to start the file with two bytes containing 255's (or $FF to those HEXadecimal hacks out there. Yes, we know who we are If) as a file header. A loader program will generate an error if during a load it does not first encounter these two bytes. The next two bytes contain the starting address, the location where the binary load is to begin. The micro-processor expects to see addresses with the low byte first, high byte second (for a hex address of $1234 for example, the first byte would be $34, and the second would be $12) and so for conformity, the binary loader handles memory addresses in the same way. Now that the loader knows where to start loading, it next needs to know how many bytes to load into memory. The next two bytes however, do not contain this information, but they do contain the next best thing, the ending address of the binary load, in low byte first, high byte second format. The bytes that follow are what make up the actual machine language program. No, that's not entirely true. It is only the ENDING ADDRESS minus the STARTING ADDRESS number of bytes that are loaded, If the end-of-file (EOF) has not been reached, then it tries to load another block of memory by looking for another starting address (low byte, high byte), another ending address (low byte, high byte), and more machine language data. In this way, a binary load file can load data into low memory, into high memory, and memory in between.
Now that you understand that (I hope!), we can discuss my problem. After a binary file is loaded into memory, we need to find a way to start it executing. If it is going to just sit there, it is of no use to us. There are three ways of giving life to your creation. # 1, use the USR function in BASIC, #2, use the (M) Run At Address command in DOS, or #3, use the G command of the Debugger that resides in the Editor/ Assembler Cartridge (or OSS's EASMD for that matter). But I have heard stories of load file software running itself after loading. If this has ever happened to you, please do not try to exorcise evil spirits, for it is perfectly natural. There is a fourth way to run your software.
There are two secret (not any more, eh!) bytes in DOS which contain the address that the loader program jumps to after every memory load. Normally, these two bytes point to the routines to load another block of memory, but since these two bytes are located in RAM, they can be changed. Give you any ideas! If we change these two bytes to point to the entry point of OUR routine instead of THEIR routine, our program will start up immediately after loading! Wonderful, isn't it!!
Now for the particulars. The starting address of these two bytes is 736 decimal (for you HEX hacks, better make it $2E0). Now comes the fun part. To get your load files to run automatically, six bytes (is that all?) must be appended onto your files. The first two bytes are the starting address of 736 (or $2E0 HEX), low byte first (224 or $E0 HEX), high byte second (2 or $02 HEX). Then comes the ending address of 737 (or $2E1 HEX), again using the low byte (225 or $El HEX), high byte (2 or $02 HEX) sequence. Sound familiar? The last two, and final bytes contain the entry point address of YOUR software. I am not a mind reader, so I cannot tell you what the numbers should be, but only that they should also be in reversed (low byte, high byte order). In Assembly language, it would look like this:
0900 *=$02E0 ;Generates START and END addresses
0910 WORD INTRO;Your execution address here!
Now for a word of warning! The Auto-boot has to be the last block in a binary file. Take it from someone who knows. I wrote a program and put the auto-boot at the beginning. The subsequent load file was 32 sectors longs and you can imagine my surprise when it tried to run itself after loading only one of those 32 sectors. This had me going crazy for a whole weekend! What had happened, if you haven't already guesses, was that the DOS had loaded the new Auto-boot address into its RAM location and proceeded to run my space war program, even before the game was loaded into memory. Like jumping into a swimming pool before the water is put in!