A.N.A.L.O.G. ISSUE 24 / NOVEMBER 1984 / PAGE 58
Editor’s note: This issue, Tom Hudson’s Boot Camp gives way to BOFFO, a utility for assembly language programmers. Boot Camp readers are encouraged to study the use of BOFFO for next issue’s Boot Camp column, which will examine the use of assembly language subroutines in BASIC.
For the assembly language programmer, there’s probably no worse drudgery than converting object code into DATA statements for use in BASIC programs. This was a major concern for the ANALOG Computing programming staff (all of us being basically lazy), so BOFFO was developed and improved, a little bit at a time, over a period of about a year.
BOFFO will convert just about any file into DATA statements, so that it can be reconstructed or POKEd into memory by a BASIC program. The DATA statements can be created with a simple checksum if desired—a good idea for magazine programs, which are easily mistyped.
BOFFO is intended primarily for experienced programmers who would like an easy shortcut in generating BASIC DATA.
After typing in the accompanying program listing, check your typing with D:CHECK2 and SAVE the program to disk.
When RUN, BOFFO will ask you several questions about what you want to do. Here’s a brief explanation of each:
OBJ/DATA file?If you’re converting an assembler object file, type O and press RETURN; otherwise, type D and press RETURN.
Typing O will force BOFFO to read the machine language load header bytes, placing only actual memory bytes into the DATA statements. Note that the memory in your object file must be contiguous. That is, each group of loaded data must start loading in the first byte after the previous group. If not, an error message will result. Use the O option for object files only!
Typing D will cause BOFFO to place every byte of the file into the DATA statements. Use the D option for text files or object files which you’d like to completely reconstruct.
OBJECT filename? DATA filename?Depending on whether you chose the O or D option, one of the above questions will appear. In either case, type in the name of the file you wish to convert. If you enter a filename without a device, D1: is assumed.
BASIC filename?At this point, enter the name of the file you want to create. This file will contain the BASIC DATA statements which correspond to the input file. If you have a printer, you can send the output to it by typing P:. Usually, you’ll want to send the output to a disk file, like so: D:FILENAME.EXT.
Most errors in filename entry will be trapped, and you will be asked to try again.
Starting lineno?Type in the line number you want the DATA statements to start on.
Line increment?Type in the line number increment. For example, if you use a starting line number of 1000 and an increment of 5, the line numbers will proceed: 1000, 1005, 1010, and so on.
Decimal/Hex?Typing D here will cause BOFFO to generate decimal (base 10) numbers in the DATA statements. This is the form of data that is used most often.
Typing H here will generate hexadecimal DATA statements, like those seen in most of ANALOG Computing’s assembly language games. The hexadecimal form saves a great deal of memory, but you must decode the hex values, which is a slow process. Look at any of ANALOG Computing’s assembly games to see how this is done.
Bytes per line?Simply enter the number of data bytes you want on each DATA line. Usually, 25 is the maximum for decimal values, and 45 the maximum for hex. Of course, you could put only one byte on each line, but this would waste memory.
Checksum (Y/N)?If you want BOFFO to generate checksum values, type Y and press RETURN. If not, type N.
The checksums generated by BOFFO are simple, modulo 1000 numbers. To get the checksum, add the value of each byte in the line to a counter. If the value of the counter ever exceeds 999, subtract 1000 from it. The checksum is placed after the last byte in each DATA line; simply READ it after you have read all the data bytes. Figure 1 shows the code necessary to process checksums for DATA statements containing 25 bytes per line.
10 TRAP 100 20 FOR X=1 TO 25 30 READ BYTE 40 TOTAL=TOTAL+BVTE 50 IF TOTAL>999 THEN TOTAL=TOTAL-1000 60 NEXT X 70 READ CHKSUM 80 IF TOTAL<>CHKSUN THEN ? "DATA ERROR!" 90 GOTO 20 100 IF PEEK (195)=6 THEN ? "DATA OK!":END 110 ? "DATA ERROR :"; PEEK (195) :END
Note that the checksum values carry on from one DATA line to the next. In this way, if a line is missing, it can be detected and fixed.
You don’t need checksums for your own programs. I usually only generate checksums if the finished program is going to be printed in ANALOG Computing, or where someone will have to type it in. Using checksums definitely helps the end user reduce typing errors.
After you’ve answered all BOFFO’s questions, it will generate the BASIC DATA and write it to the specified output file. When the READY prompt appears, you’re ready to use the DATA.
To retrieve your newly-created BASIC code, you must ENTER it. The ENTER command is similar to LOAD, except that the code is added to whatever BASIC code is in memory. Type ENTER "D:FILENAME.EXT". The DATA code will be brought into memory, ready for you to use.
At the end of the DATA statements, BOFFO creates a REM statement which lets you know how many bytes were converted. This is a convenient way to tell how many bytes the program needs to READ.
An important restriction in BOFFO is that data blocks in object data files must be contiguous. Otherwise, there is no way to determine where in memory the code resides.
Remember that BOFFO is meant for fairly advanced programmers. You should know what you want to do with the code once it is converted to DATA. If you don’t know what “object code” is, BOFFO isn’t for you.
I think most assembly language programmers will agree that BOFFO is a utility that’s worth typing in. It has saved me literally hundreds of hours — and many headaches — when setting up ANALOG Computing’s assembly language games. Why translate all those bytes, when your Atari can do it for you!
10 TRAP 40000:? "}ASSEMBLY-TO-BASIC DATA CONVERTOR":? "↓By Tom Hudson, ANALOG Computing" 20 DIM FILE$(15),FI$(17),D$(1),HX$(16),DH$(1),CK$(1),OD$(1),ODMSG$(6):HX$="0123456789ABCDEF" 30 POSITION 2,5:? "↑↑ OBJ/DATA file";:INPUT OD$:IF OD$="O" THEN ODMSG$="OBJECT":GOTO 60 40 IF OD$<>"D" THEN 30 50 ODMSG$=" DATA" 60 POSITION 2,7:? "↑↑";ODMSG$;" filename";:INPUT FILE$:TRAP 120:IF LEN(FILE$)=1 THEN 90 70 IF FILE$(2,2)=":" THEN FI$=FILE$:GOTO 100 80 IF FILE$(3,3)=":" THEN FI$=FILE$:GOTO 100 90 FI$="D:":FI$(3)=FILE$ 100 OPEN #1,4,0,FI$:IF OD$="O" THEN GET #1,BYTE:GET #1,BYTE2:IF BYTE<>255 OR BYTE2<>255 THEN 130 110 GOTO 150 120 ? FILE$;" INVALID FILE,";:GOTO 140 130 ? FILE$;" NOT OBJ FILE,"; 140 ? " PRESS RETURN";:INPUT D$:CLOSE #1:GOTO 60 150 POSITION 2,9:? "↑↑ BASIC filename";:INPUT FILE$ 160 TRAP 200:IF FILE$(2,2)=":" THEN FI$=FILE$:GOTO 190 170 IF FILE$(3,3)=":" THEN FI$=FILE$:GOTO 190 180 FI$="D:":FI$(3)=FILE$ 190 OPEN #2,8,0,FI$:GOTO 210 200 ? FILE$;" INVALID FILE, PRESS RETURN";:INPUT D$:CLOSE #2:GOTO 150 210 POSITION 2,11:? "↑↑Starting lineno";:TRAP 210:INPUT LINE:TOTAL=0 220 POSITION 2,13:? "↑↑ Line increment";:TRAP 220:INPUT INC 230 POSITION 2,15:? "↑↑ Decimal/Hex";:INPUT DH$:IF DH$<>"D" AND DH$<>"H" THEN 230 240 POSITION 2,17:? "↑↑ Bytes per line";:TRAP 240:INPUT BLIN 250 POSITION 2,19:? "↑↑ Checksum (Y/N)";:INPUT CK$:IF CK$<>"Y" AND CK$<>"N" THEN 250 260 COUNT=0:TRAP 420 270 IF OD$="D" THEN LA=0:HA=65535:TOTLEN=65536:TLC=-1:GOTO 310 280 GET #1,LO1:GET #1,HI1:GET #1,LO2:GET #1,HI2:LA=LO1+HI1*256:HA=LO2+HI2*256:TOTLEN=HA-LA+1:TLC=-1 290 IF HA=737 AND LA=736 THEN 420 300 IF COUNT>0 AND LA<>LL+1 THEN ? ".}ERROR!!! MEMORY NOT CONTIGUOUS!":END 310 LL=HA:IF TOTAL>0 THEN 330 320 X=-999 330 TLC=TLC+1:IF TLC=TOTLEN THEN 270 340 GET #1,BYTE:TOTAL=TOTAL+1:COUNT=COUNT+1:GNDTOT=GNDTOT+BYTE:IF CK$="Y" AND GNDTOT>999 THEN GNDTOT=GNDTOT-1000 350 IF X=-999 THEN ? #2;LINE;" DATA ";:LINE=LINE+INC:X=0 360 IF DH$="D" AND X>0 AND X<BLIN THEN ? #2;","; 370 X=X+1:IF DH$="H" THEN BH=INT(BYTE/16):BL=BYTE-(BH*16):? #2;HX$(BH+1,BH+1);HX$(BL+1,BL+1);:GOTO 390 380 ? #2;BYTE; 390 IF X<BLIN THEN 330 400 IF CK$="N" THEN ? #2:GOTO 320 410 ? #2;",";GNDTOT:GOTO 320 420 IF PEEK(195)<>136 AND PEEK(195)<>0 THEN ? ".}ABNORMAL TERMINATION (ERROR ";PEEK(195);")":END 430 IF CK$="N" OR X=-999 THEN 490 440 IF DH$="D" THEN 470 450 ? #2;"00";:TOTAL=TOTAL+1:X=X+1:IF X<BLIN THEN 450 460 GOTO 480 470 ? #2;",0";:TOTAL=TOTAL+1:X=X+1:IF X<BLIN THEN 470 480 ? #2;",";GNDTOT 490 ? #2:? #2;LINE;" REM * ";TOTAL;" BYTES":CLOSE #1:CLOSE #2:END