A.N.A.L.O.G. ISSUE 24 / NOVEMBER 1984 / PAGE 58

BOFFO

16K Cassette or Disk

by Tom Hudson

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.

Using the program.

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
Figure 1.

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.

Using the output.

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.

Some final notes.

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!

BOFFO
BASIC Listing

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