Classic Computer Magazine Archive COMPUTE! ISSUE 59 / APRIL 1985 / PAGE 112

Creating Atari
Machine Language Strings

Tom Sak

This clever utility program converts a machine language subroutine into fast-executing BASIC string statements and stores them on disk for later use. Requires at least 16K RAM.


The most common way to use a machine language subroutine in a BASIC program is to convert the object code into decimal numbers, put the numbers into DATA statements, then READ the numbers and POKE them into memory.
    However, if you'd like your programs to initialize faster, or if you're running short of memory, there's a better technique you should consider: converting the machine language into strings. Using string assignment statements instead of DATA statements not only saves the time required to POKE the numbers into memory, it also consumes only about one-third as much RAM. The main limitation of this technique is that the machine language routine must be completely relocatable-not a serious handicap for short (under 256-byte) routines.
    The listing following this article, "ML String Creator," is a self-modifying BASIC program that automatically creates string assignment statements from your object code and LISTS them to disk for inclusion in other BASIC programs.

Direct Execution From A String
The string technique works because, essentially, these statements are equivalent:

CJ 10 DATA 33,37,106,47,122,65
OD 30 A$="!%j/zA"

    If your subroutine contains internal JMPs or JSRs, which are not relocatable, you must use the conventional DATA statement technique. Until a BASIC program runs, you don't know where a certain string will end up in memory; therefore, if you encode your machine language (ML) into a string, it will end up at an unpredictable memory address. However, when the ML is relocatable, it is possible to execute the subroutine directly from the string with a statement like this:

50 X=USR(ADR(A$))

    The ADR() function lets you find the beginning address of the string (and therefore of your subroutine). Of course, this assumes you have previously encoded the ML into the string variable A$ with ML String Creator.
    The string assignment statement also is preferable when you're trying to squeeze a few more bytes into limited memory. Each ML byte has a decimal value in the range of 0-255. Representing this in a decimal DATA statement requires as many as three bytes, plus a comma to separate the entries. In a string assignment, each ML byte is represented as a single character.
    There are a few other limitations, however. It's not possible to represent the decimal values 155 or 34 inside quotes in a string assignment. The value 155 represents a carriage return or end-of-line marker which cannot be embedded in the assignment statement, even as part of an escape sequence. The value 34 represents the double-quote character used as a delimiter in the assignment statement.

Stringing It All Together
Keeping these limitations in mind, you can use ML String Creator to locate an ML subroutine somewhere in memory, turn it into one or more string assignment statements, and LIST the statements to disk. It is your responsibility to initially load the ML into memory. If you're using an assembler that lets you switch back to BASIC without erasing memory, you can assemble directly to memory and then load ML String Creator to convert the object code into strings.
    The program begins by requesting that you supply the first and last memory addresses (in decimal) of your routine, the name of the string variable to be created, and a line number for the first string assignment statement. A maximum of 80 bytes can be contained in a single statement string, and the maximum ML program length accommodated by the program is 256 bytes. The string variable name is limited to seven characters, including the trailing $ symbol which must be present. Finally, the line number for the first string assignment statement must be greater than 190. Subsequent lines are numbered in increments of ten.
    ML String Creator is self-modifying; the string assignment statements become a part of the program. However, the part of the program which is taking care of business protects itself from modification. The program can be used repeatedly without being reloaded, but it will grow in size.
    The self-modification feature is also used to produce a LIST statement at line 150. In the listing below it appears as a REM statement, but after the string assignment statements are created it will be modified.
    Finally, ML String Creator will prompt you for the filename of the disk file in which it will store the assignment statements. This filename and the first and last statement numbers of the created statements are concatenated with 150 LIST, in addition to the appropriate commas and double quotes, to form a genuine LIST statement.

Checking For Quotes And Carriage Returns
Before retiring, the program will indicate the memory locations, if any, at which a decimal value of either 155 or 34 was encountered. The program substitutes a value of zero in these instances. If more than ten occurrences of 155 or 34 are detected, the program stops with an error message.
    The technique used to create the strings consists of printing string assignment statements on a previously cleared screen, just as you would do from the keyboard if you were typing in a BASIC program. After the last string assignment statement is placed on the screen, a CONT statement is written on the screen in immediate mode (that is, with no statement number).
    Another feature of the program is its automatic RETURN. Normally when you press RETURN after typing a BASIC statement, the statement is either immediately executed (for example, LIST) or incorporated into your BASIC program (for example, 10 A=B*C). The Atari has a switch which makes pressing the RETURN key optional. The switch is location 842, which usually contains a 12. POKE 842,13 switches to automatic RETURN.

Brace Yourself For Fast Action
Processing takes place rapidly when the computer presses RETURN, so be prepared. The commands to be processed must be both correct and in the right place on the screen, and the cursor must be positioned on or above the first statement. If an error is detected, a message will be written on the screen, but the Atari, using the automatic RETURN, will process the error message as a command and a syntax error will result.
    Lines 50 and 70 write the string assignment statements onto the screen. Line 85 places CONT on the screen and positions the cursor at the top, well above the first statement to be processed. The switch at location 842 is set at line 90. Then the program is stopped. When you are entering BASIC statements from the keyboard, you don't have one of your BASIC programs executing, and that is what is happening here, except that the text is "typed," the cursor is positioned, and RETURN supplied by the computer.

Watching The Atari Type
If you want to watch this action, you can see most of it by looking at the screen carefully. Insert the following statement to see what the screen looks like immediately before processing:

86 GOTO 86

    Press BREAK to regain control; a STOPPED AT LINE 86 message will be displayed, destroying portions of the information which you are attempting to view.
    The figure below depicts a typical screen image immediately following the STOP statement in line 90 and just before the automatic RETURN. (Of course, the actual string characters will vary depending on the ML subroutine you are reading.) Don't forget to delete line 86 when you've seen enough.

screen image

    The CONT statement is the last one executed by the flying cursor before it returns control to your program. (The immediate execution of GOTO 100 would have the same effect.) The same technique is used to create and incorporate the LIST statement.
    With a little imagination, you can modify this program to accept other forms of input of decimal or hexadecimal values to be converted to character strings, or to accept an ML object file from disk.
    If you are interested in adapting some of these techniques to your own programs, there are a few things to watch out for. First, when placing the cursor at the top of the screen prior to activating the automatic RETURN, be sure to allow sufficient room so the screen text produced by the STOP statement won't overwrite the statements which your program placed on the screen. Second, be sure to turn off the automatic RETURN (POKE 842,12) when you're done.

ML String Creator
Please refer to "COMPUTEI's Guide To Typing In Programs" before entering this listing.

PF 1 REM ML STRING MAKER
HA 2 REM Writes string assignment sta
     tements from up to 256 memory lo
     cations and LISTS them on disk.
AJ 10 DIM NAME$(10),RTN(11),RTN1(11)
EC 20 ? CHR$(125);"ENTER -":? "START
      ADDRESS";:INPUT FBA:? " END ADD
      RESS";:INPUT LBA
JN 25 ? " STRING NAME";:INPUT NAME$:?
       " FIRST STATEMENT NUMBER";:INP
      UT FSN:SN=FSN-10:1=LEN(NAME$)
CC 30 IF LBA<FBA OR LBA-FBA>255 OR I<
      2 OR I>7 OR NAME$(I,I)<>"$" OR
      FSN<191 THEN ? CHR$(253):GOTO 2
      0
OM 35 ? CHR$(125):? :DISP=-79:FBA=FBA
      -80
OJ 40 SN=SN+10:FBA=FBA+80:DISP=DISP+B
      0:IF FBA?LBA THEN GOTO 85
FL 45 RANGE=79:IF LBA-FBA<79 THEN RAN
      GE=LBA-FBA
FO 50 ? SN;" ";NAME$;"(";DISP;")=";CH
      R$(34);:FOR I=FBA TO FBA+RANGE:
      J=PEEK(I)
DC 60 IF J=155 THEN J=0:K=K+1:RTN(K)=
      I:IF K=11 THEN 190
DI 65 IF J=34 THEN J=0:L=L+I:RTNI(L)=
      I:IF L=11 THEN 190
AL 70 ? "{ESC}";CHR$(J);:NEXT I:? CHR
      $(34)
AJ 75 GOTO 40
FP 85 ? "CONT":POSITION 0,0
EG 90 POKE 842,13:STOP
ON 100 POKE 842,12
CN 110 ? CHR$(125);"ENTER -":? " FILE
       NAME";:INPUT NAME$
LA 120 ? CHR$(125):? :? :? "150 LIST"
       ;CHR$(34);"D:";NAME$;CHR$(34);
       ",";FSN;",";SN-10:? "CONT":POS
       ITION 0,0
HB 130 POKE 842,13:STOP
P8 140 POKE 842,12
NM 145 ? CHR$(125);"LISTING ";NAME$
DK 150 REM LIST statement will be ins
       erted here.
LP 160 ? CHR$(125):IF K>0 THEN ? "Zer
       o substituted for 155 @":FOR I
       =1 TO K:? " ";RTN(I);:NEXT I
NF 170 IF L>0 THEN ? :? "zero substit
       uted for 34 @":FOR I=1 TO L:?
       " ";RTN1(I);:NEXT I
HA 180 END
ED 190 ? CHR$(125):? "TOO MANY 155s A
       ND/OR 34s":END