You've just bought your Assembler Editor cartridge, and you're starting to get into machine language programming. Hold it, before you go any further. If you haven't already heard, your assembler manual is chock full of errors. Run, don't walk, to the Atari hot line to request their errata sheets. It will save you grief and headaches, especially if you are cassette dependent.
After writing and debugging your first machine language program with your Assembler Editor cartridge, you can now save it to cassette or disk as a binary file. You can also load it back into the computer and run the machine language program directly. But what if you want to combine this routine with a BASIC program? This is the objective of a majority of beginning machine language programmers. If you look on pages 66-67 of the Assembler Editor manual, you will find a merger program. However, the program is clumsy and unwieldy, especially in its handling of problem code values (such as the one which is the ATASCII equivalent of quotation marks).
To overcome this problem, I've provided Program 1. This program will take your machine language and automatically convert it into a complete BASIC subroutine. This can then easily be added to your BASIC program. The subroutine is complete within itself. It requires only:
- That your program have line numbers no greater than 31000.
- That you call the subroutine as early as possible in your program.
This will allow you to reuse the subroutine variables in your program if you wish. Also the DIMension statements will be declared at the start of the program.
This utility program has a great deal of flexibility built-in. You can choose to store your machine language in a variety of ways:
- As strings (probably the safest and most versatile method). The program will automatically generate the strings plus the DIMension statements to support them. It also will take care of the troublesome codes of 34 (ATASCII for quotes) and 155 (ATASCII for RETURN).
- Storage at a specific location in memory. The location can be the same as specified in your binary file or it can be changed. The program will then generate a series of DATA statements. It will also provide a short routine that will READ the data and POKE it into memory.
- Any number and combination of string and location storage can be used. The program will combine them into a single subroutine to set them up all at once. Just merge with your BASIC program and add a GOSUB to this subroutine.
- The program will check your keyboard input and prompt you when you've made an error.
The program, as written, sits in slightly less than 5K bytes of RAM after DIMensioning of arrays and strings. I've run it through the "Masher" program from the Atari Program Exchange. However, this saves only about 500 bytes. The program also then becomes very difficult to follow. So I've kept it as is. Type the program in and LIST it to disk or cassette. Don't SAVE it.
To use the utility program, first store your machine language to disk or cassette as a binary file. If your source program is in RAM, this can be done through the assembler with this command: ASM,,#D:<filename> for disk or ASM,,#C: for cassette.
Note that what you wrote was the source code, not the actual object code which is the machine language program. Once you've done the above, turn off the computer to wipe out the source program. Then remove the Assembler cartridge, insert the BASIC cartridge, and boot the DOS into memory.
If your program has already been assembled (converted to machine language) and the final machine language resides in RAM, then do the following:
For Disk | ||
SAVE #Disk File<starting address<end of routine address Example: SAVE #D:PROGRAM.OB]<1400<17FF |
||
For Cassette | ||
SAVE #C:<start address<end address Note that all addresses are in a hexadecimal. |
Again, shut off the computer and replace the Assembler with the BASIC cartridge.
To use this utility both the utility and the machine language program must be in RAM. The utility program occupies about 5K bytes of memory. Thus you must be careful to locate your machine language program so that it does not interfere with the BASIC program. You can locate the machine language either in page 6 or high up in memory just below the display list. To help you with the second method, the tables below define usable and safe living space for your machine language program.
Computer RAM Installed |
Suggested Safe Memory | |||
---|---|---|---|---|
Decimal | Hexadecimal | |||
From | To | From | To | |
8K | Not enough memory | |||
16K | 12750 | 15390 | 31CE | 3C1E |
24K | 12750 | 23582 | 31CE | 5C1E |
32K | 12750 | 31774 | 31CE | 7C1E |
40K | 12750 | 39966 | 31CE | 9C1E |
48K | 12750 | 39966 | 31CE | 9C1E |
Note: Assumes that you are in GRAPHICS 0, that the BASIC cartridge is installed, and that the first part of DOS 2.0S (mini-DOS) is loaded. The mini-DOS occupies 5628 bytes. |
Computer RAM Installed |
Suggested Safe Memory | |||
---|---|---|---|---|
Decimal | Hexadecimal | |||
From | To | From | To | |
8K | 7100 | 7198 | 1BBC | 1C1E |
16K | 7100 | 15390 | 1BBC | 3C1E |
24K | 7100 | 25382 | 1BBC | 5C1E |
32K | 7100 | 31774 | 1BBC | 7C1E |
40K | 7100 | 39966 | 1BBC | 9C1E |
48K | 7100 | 39966 | 1BBC | 9C1E |
Note: Assumes that you are in GRAPHICS 0 and that the BASIC cartridge is installed. |
To convert your machine language to BASIC, proceed as follows:
- Load your machine language subroutine into its safe area. If from disk, first load the second part of DOS and then use option L (Binary Load). Then go back to BASIC. If you have a cassette, be careful. Page 65 of the Assembler Editor manual tells you to CLOAD your machine language. Trying that can give you a headache. The errata sheets from Atari give you a routine for cassette loading.
- ENTER the utility program which has previously been LISTed to disk or cassette (see step 6 if you are using cassette).
- RUN the program. The program will ask for the starting and ending addresses of your machine language routine in RAM. Answer in decimal only! All keyboard inputs for this program must be in decimal form.
- The program will then ask which method you desire for storage of your machine language. If you wish string storage, you will be prompted for the string name. You will also be asked if you wish a printout of the data to be inserted into the string. If so, you will be prompted to tum on the printer.
- If you desire to store machine language at a specific location, you will be asked if you wish storage at the same memory location as specified in step 3. Alternatively, you can store it at a different location.
- Finally you'll be asked if you wish to make any additional conversions. If yes, the program will loop back. If not, the computer will CLOSE all files and END. Your BASIC subroutine will be stored on disk as a file labelled MLR.LST. If you are using a cassette, see Program 2 for required program modifications.
-
After you're done, erase the utility program via NEW Now enter your BASIC program. Finally, merge your machine
language into your program by:
For Disk ENTER "D:MLR.LST" For Cassette See Program 2 - Now that the two programs are merged, type in a GOSUB statement to reference the first line number of MLR.LST (or the equivalent cassette file).
And that's it; you're ready to go.
I'd like to make some comments on storage of machine language in a string format. First, to do it correctly, you must write routines which are relocatable. That is, they must not contain any JMP or JSR instructions to a specific memory location within the program. Since the string can be located nearly anywhere in memory, nonrelocatable code will almost surely crash the computer. It's best to store your subroutines and data tables in page 6 of memory. These permanent addresses can then be safely called from within your routine.
Another problem lies in proofreading your string. If you load your data into a string and then PRINT it to the screen, you will see many weird and wondrous things. What is happening is that the screen editor is interpreting the function of the printed graphics symbols and carrying out the function. For example, if the graphics symbol in your string is that for a "delete character," the computer will slavishly do it. Thus the string symbols seen on your screen are not correct (unless you're lucky). To check your string, use the following routine in direct mode. (First RUN your program to DIMension and initialize your string):
L=LEN(string name$):FOR X=1 TO L:?ASC(string name$(X,X));",";:NEXT X
This routine prints the actual value of each byte stored in the string.
Another serious problem with string storage of data is the occurrence of values of 34 or 155. The value 34 is the ATASCII representation of quotation marks. The value 155 is the ATASCII for RETURN. The presence of either will cause the screen editor to prematurely truncate your string and give you an error message. Thus the program does the following when it encounters either value:
- It inserts a space character in the string and notes the position in the string.
- It then writes the BASIC subroutine statements so that the values are inserted into the string without going through the screen editor. It uses the CHR$ function for this purpose.
- As presently set up, the program can handle up to 15 values of the quotes and of the RETURN characters. It checks for the total occurrence of these and warns you if there are too many.
There you have it. I hope this program makes the difficult world of machine language a little more enjoyable.
A$ | Used to receive yes or no responses | |
BATOP | Top memory location of utility program | |
D0$ | Holds name of string used to store machine language (ML) | |
F | Flag. Zero if string storage requested. Set to one if storage at a specific address is requested | |
I,S,T,X,Y | Loop counters | |
L | Length of string required to store ML | |
LS,LF | Initial and final position in string to be filled with data | |
LN | Line number of subroutine to be written for string storage | |
LNO | Line number of DATA statements to be written for ML storage at a specific address | |
LR | Remaining length of string after subtracting 80 | |
N | Input value for choice of ML storage | |
QT | Total number of values of 34 in ML | |
QUOTE() | Holds position in string of ATASCII values of 34 | |
RT | Total number of values of 155 in ML | |
RETRN() | Holds position in string of ATASCII values of 155 | |
S | Temporary value for ML address | |
SF,FF | New starting and final address of ML | |
SO,FO | Initial starting and final address of ML | |
V | Counter to indicate number of routines to be stored at specific addresses | |
X | Indicates cell in array RETRN() | |
Z | Indicates cell in array QUOTE() |
10 CLR :GRAPHICS 0:POKE 752,1:POKE 756,209:? "{5 SPACES}MACHINE LANGUAGE CONVERTER":GOSUB 600:POKE 756,224 20 DIM A$(1),D0$(3),QUOTE(14),RETRN(14) 30 D0$="{3 SPACES}":TRAP 580:GOSUB 740:V=0:OPEN #3,8,0,"D:MLR.LST":LNO=32050:LN=31000:F=0 40 ? :? :? "INPUT STARTING ADDRESS OF CODE":POKE 752,0:GOSUB 590:INPUT S:SO=S:SF=S 50 ? "INPUT FINAL ADDRESS OF CODE":GOSUB 590:INPUT S:FO=S:FF=S:GOSUB 640 60 ? "STORAGE METHOD FOR ROUTINE7":? "{3 SPACES}1.AT SAME ADDRESS":? "{3 SPACES}2.WITHIN A STRING" 70 ? "{3 SPACES}3.AT NEW ADDRESS?" 80 GOSUB 590:? :? "PLEASE TYPE NUMBER PLUS RETURN!":INPUT N 90 IF (N<>1 AND N<>2 AND N<>3) THEN ? "{BELL}WRONG RESPONSE!TRY AGAIN!":GOSUB 600:GOTO 60 100 IF N=3 THEN ? :? "NEW STARTING ADDRESS FOR ROUTINE?":GOSUB 590:INPUT S:SF=S 110 IF N=3 THEN ? "NEW FINAL ADDRESS FOR ROUTINE!":GOSUB 590:INPUT S:FF=S 120 IF N=3 THEN IF FF-SF<>FO-SO THEN ? "{BELL}INCORRECT FINAL ADDRESS! TRY AGAIN!":? :GOTO 110 130 IF N=1 OR N=3 THEN F=1:V=V+1:GOTO 180 140 L=FO-SO+1:GOSUB 680:GOSUB 610 150 ? "DO YOU WISH AN ASCII PRINTOUT":? "OF YOUR STRING DATA!":GOSUB 590:INPUT A$ 160 IF A$="Y" THEN N=4:? "HIT RETURN WHEN THE PRINTER IS ON!":GOSUB 590:INPUT A$:OPEN #2,8,0,"P:" 170 GOTO 260 180 ? #3;LNO;" DATA ";SF;",";FF:LNO=LNO+10 190 ? #3;LNO;" DATA "; 200 FOR I=0 TO 19 210 IF SO+I=FO+1 THEN POP :IF I THEN ? #3;",";-1:? #3:LNO=LNO+10:GOTO 490 215 IF SO+I=FO+1 THEN IF I=0 THEN ? #3;-1:? #3:LNO=LNO+10:GOTO 490 220 IF I THEN ? #3;","; 230 ? #3;PEEK(SO+I); 240 NEXT I:? #3:LNO=LNO+10:SO=SO+20:GOTO 190 260 IF N=4 THEN ? #2:? #2;"**DATA FOR ";D0$;"**" 270 LS=1:Z=0:W=0:? #3;LN;" DIM ";D0$;"(";L;"):"; 280 IF N=4 THEN FOR I=0 TO L-1:? #2;PEEK(SO+I);:IF I<L-1 THEN ? #2;","; 290 IF N=4 THEN NEXT I 300 LR=L-80:IF LR<=0 THEN LF=LS+L-1 310 IF LR>0 THEN LF=LS+80-1:L=LR 320 ? #3;D0$;"(";LS;",";LF;")=";:? #3;CHR$(34);:FOR I=LS TO LF 330 IF PEEK(SO+I-1)=34 THEN ? #3;" ";:QUOTE(Z)=I:Z=Z+1:GOTO 360 340 IF PEEK(SO+I-1)=155 THEN ? #3;" ";:RETRN(W)=I:W=W+1:GOTO 360 350 ? #3;CHR$(PEEK(SO+I-1)); 360 NEXT I:IF LR>0 THEN LS=LS+80:? #3;CHR$(34):? #3:LN=LN+10:? #3;LN;" ";:GOTO 300 370 ? #3;CHR$(34):? #3:LN=LN+10 380 QT=0:RT=0:FOR I=0 TO 14:IF QUOTE(X) THEN QT=QT+1 390 IF RETRN(X) THEN RT=RT+1 400 NEXT X:IF QT=0 AND RT=0 THEN 490 410 ? #3;LN;"RESTORE ";LN+20:LN=LN+10 420 IF QT THEN ? #3;LN;" FOR X=1 TO ";QT;":READ Z:";D0$;"(Z,Z)=CHR$(34):NEXT X":LN=LN+10 430 IF QT THEN ? #3;LN;" DATA ";:FOR Y=0 TO QT-1:? #3;QUOTE(Y);:IF Y AND Y<QT-1 THEN ? #3;","; 440 IF QT THEN NEXT Y:? #3:LN=LN+10 450 IF RT THEN ? #3;LN;" FOR X=1 TO ";RT;":READ Z:";D0$;"(Z,Z)=CHR$(155):NEXT X":LN=LN+10 460 IF RT THEN ? #3;LN;" DATA ";:FOR Y=0 TO RT-1:? #3;RETRN(Y);:IF Y AND Y<QT-1 THEN ? #3;","; 470 IF RT THEN NEXT Y:? #3:LN=LN+10 490 GOSUB 740:? "ALL DONE":GOSUB 590:INPUT A$ 500 IF A$="N" THEN D0$="{3 SPACES}":CLOSE #2:GOTO 40 510 IF F=0 THEN 570 520 ? #3;"32000 W=0:V=";V;":RESTORE 32050" 530 ? #3;"32010 READ X,Y:FOR I=X TO Y:READ Z:POKE I,Z:NEXT I" 540 ? #3;"32020 READ Z:IF Z<>-1 THEN ?";CHR$(34);"ERROR IN CODE! CHECK DATA STATEMENTS!";CHR$(34);":END" 550 ? #3;"32030 W=W+1:IF W<V THEN 32010" 560 ? #3;"32040 RETURN" 570 CLOSE #2:CLOSE #3:END 580 CLOSE #2:CLOSE #3:TRAP 40000:? "{BELL}ERROR ";PEEK(195);" AT LINE ";PEEK(186)+256*PEEK(187);"!":END 590 FOR T=10 TO 6 STEP -1:FOR S=8 TO 0 STEP -1:SOUND 0,15-S,10,T:NEXT S:NEXT T:SOUND 0,0,0,0:RETURN 600 FOR T=1 TO 400:NEXT T:RETURN 610 ? :? "INPUT TWO CHARACTER STRING NAME":? "PLUS THE $":GOSUB 590:INPUT D0$ 615 IF LEN(D0$)<3 THEN GOSUB 750:GOTO 610 620 IF ASC(D0$(1,1))>90 OR ASC(D0$(1,1))<65 OR D0$(2,2)="$" OR D0$(3,3)<>"$" THEN GOSUB 750:GOTO 610 630 RETURN 640 IF SO<1792 THEN RETURN 645 IF FO>(256*PEEK(106)-1000) THEN ? "{BELL}I DON'T HAVE THAT MUCH MEMORY!":POP :GOTO 40 650 BATOP=PEEK(144)+256*PEEK(145):IF BATOP>SO-100 THEN ? "{BELL}CAUTION! THIS PROGRAM MAY HAVE ":GOTO 670 660 RETURN 670 ? "OVERRUN YOUR CODE! CHECK YOUR RESULTS!":GOSUB 600:RETURN 680 QT=0:RT=0:FOR I=0 TO L-1:IF PEEK(SO+I)=34 THEN QT=QT+1 690 IF PEEK(SO+I)=155 THEN RT=RT+1 700 NEXT I:IF RT<16 AND QT<16 THEN RETURN 710 ? "{BELL}WARNING! YOUR CODE CONTAINS":? "MORE THAN 15 ATASCII VALUES FOR":? "RETURN OR QUOTES!" 720 ? "THUS I CANNOT PROCESS IT!":? "PLEASE MAKE ANOTHER CHOICE!":GOSUB 600:GOSUB 600 730 POP :GOTO 60 740 FOR I=0 TO 14:QUOTE(I)=0:RETRN(I)=0:NEXT I:RETURN 750 ? "{BELL}WRONG RESPONSE! TRY AGAIN!":RETURN
Listing. Merging ML into BASIC Disk Version.
Download (Saved BASIC) / Download (Listed BASIC)
Program 2. | Changes for Cassette Users |
(see notes below) |
30 D0$="{3 SPACES}":TRAP 580:GOSUB 740:V=0:LNO=32050:LN=31000:F=0 35 OPEN #3,8,0,"C:":? #3;"1 DATA ";:FOR I=0 TO 59:? #3;"0,";:NEXT I:? #3;"0";:? #3
Listing. Merging ML into BASIC Disk Version.
Download (Saved BASIC/full program) / Download (Listed BASIC/changes only)
Return to Table of Contents | Previous Section | Next Section