ST LOGO EXPLORATION
Mapping uncharted memoryby FRED HATFIELD
When you buy a computer that's too new to have detailed technical documentation
available, it's up to you to find out whatever you can about the internal
features. The Atari 520ST comes with two manuals. One is an attractively
illustrated users guide that gets you started with the drop-down menus
and selection of optional features, etc. The second manual is entitled
"Sourcebook for Atari Logo" and describes technical features of Logo, the
only language currently provided with the ST.
One of the tried-and-true approaches for exploring an undocumented computer is to find some way of looking at memory storage locations. Once you can look at memory, the "brute force" method of figuring out what's going on is to print out the biggest possible hexadecimal dump of memory you can manage. Then you sit down and look for obvious patterns, I/O control blocks, object code, messages, etc.
While scanning the Logo sourcebook, I noticed a primitive called .EXAMINE n that displays contents of absolute memory location n as specified by the input number. Terrific! There should be a matching .DEPOSIT n and sure enough there was! Now we could look for the best spots in the "fishing hole."
By experimenting, I discovered the .EXAMINE n limits were between $00800 and $7FFFF. (No, that's not an extra F-you're working with 24 bits now) I won't worry about that yet, I thought. All I want now is a "quick and dirty" way to read and print out memory
A simple loop finds that you can enter two addresses for start and stop locations and get data out:
TO DUMP :START :STOP
IF (:START >= :STOP) [STOP]
[TYPE .EXAMINE :START TYPE [# ]
DUMP :START :STOP]
A more useful format would consist of the address followed
by 16 successive byte values, as is the case with most standard dump formats.
Since Logo is more suited for graphics, it began to look as if necessary arithmetic routines (such as binary to hex conversion) would consume too much programming time.
Once again I thumbed through the ST Logo Sourcebook. This time I discovered a way to convert binary to hex by string substitution instead of by arithmetic. After all, we're only working with 256 possibilities, so a string substitution table doesn't take up too much of a 512K memory
Sure enough, there was an operation called PIECE which was just perfect for what I wanted to do. A previously defined string could be used for supplying the desired two hex digits in ASCII. The value of the memory contents would define the decimal position of the two-character ASCII pair desired.
I immediately built two strings, one called :HEX1 and the other :HEX2 (clever, no?). :HEX1 had the string value "000102030405 ... 7D7E7F" and :HEX2 had the rest of the combinations, "80818283 . . . FDFEFF". like so:
>MAKE "HEX1 "0001020304
Now let's test it by outputting an actual two-character
string just as we would want to do with the finished program.
We'll call it PRNT1 since it prints all values from 00 to 7F, depending on the value of the two decimal digits following the PIECE command:
TO PRINTI :A
MAKE "HCHR PIECE :A+1 :A+2 :HEX1
Then, when you test it by typing PRNT1 32 [RETURN] it responds with:
These are the 33rd and 34th characters in the :HEX1 string-and
also the hex representation of 32 decimal.
Now the remaining job is to design a procedure that calls the proper PRNT routine, depending on the value of the input variable :A. This means testing :A on entry and determining if its value is above (80 hex-128 decimal) and then calling the proper PRNT routine. Since the positions in :HEX2 are the same as :HEXl, we can compensate by subtracting 128 from all values equal to or greater than 128. The only difference between HEX1 and :HEX2 are the contents of the strings stored there-:HEX2 values are 128 higher, but in the same relative positions as :HEXl values.
Since the strings are two characters for every value, the input value :A will have to be multiplied by two somewhere. Why not do it at the beginning of the routine where we test the value above or below 128? Then you won't have to worry about it afterwards. All we have to do is double it immediately, then double the test for above or below 128-so now we test for values above or below 256.
In the end, for reasons of modularity, I broke up the strings into 8 groups of 64-:HEX1 through :HEX8, each containing 64 two-digit representations of hex values.
When the input routine PRNT receives the decimal value to be printed in hex (:B), it also receives a character count (CNT) indicating how many two-character hex representations to put on a line. The version here is 16 since that is an easy number to step in hexadecimal and the memory map representation is neater and easy to use. 16 characters to the line will also leave enough blank space on the right hand margin to make notes and draw identification arrows with copious valuable (hopefully) information.
However, if you should desire to cut your paper consumption in half by putting 32 characters to the line (or even 64 in compressed Epson print) it is easy enough to change the 16 value passed by DUMP into the value desired. But don't forget to also change the address incrementing value following the PRNT call. Otherwise, your address identifications on the first line will still be incremented by the previous value.
A note about PRNTZ. Each PRNT routine converts the requested decimal value to a two-character hex representation. That value is stored in variable :HCHR (Hex Character). It may appear that this is wasteful, since the value could be printed immediately at conversion. But by storing it in :HCHR, later versions of the dump will be able to perform smarter functions such as disassembly, memory searching, etc.
Programmers usually call this a "hook" for possible later features. So when the data has been converted by the proper PRNTn routine, all branch to the common PRNTZ location where :HCHR is printed to the screen or printer. When control returns to PRTLN9 (in routine PRTLN2), there is a command to PRINT -which is really there to supply a carriage return/line feed. In the Epson buffered printer, a line is not printed until CR/LF is received, so this simply causes the 16 double characters just sent to the line printer or screen to be displayed.
TYPING IT IN
So to start exploring your ST's memory with Logo, type in Listing 1, DUMP LOG. Be sure to type INITALL before you RUN the memory dump.
The program is stopped by pressing [CONTROL] [G]. If you just want to pause, press [CONTROL] [Z]. Type CO to continue everything from where it left off.
I discovered that this program is slow enough so that any additional tinkering might bring it to a discouraging crawl. I usually started it in the evening and let it run all night. The beginning of any computer system analysis is going to be slow and monotonous. But once you have developed this primitive tool you'll see some rapid gains.
Fred Hatfield is a New Orleans programming consultant. He wrote Reader's First ST Program in last month's Antic.
Listing 1 DUMP.LOG Download