ST LOGO EXPLORATION
Mapping uncharted memory
by FRED HATFIELDWhen 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]
END
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.
LOGO HEX
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:
?TO INIT1
>MAKE "HEX1 "0001020304
05060708090A0B0C0D0E0F1
01112131415161718191A1B
1C1D1E1F202122232425262
728291A2B2C2D2E2F303132
333435363738393A3B3C3D3
E3F40414243444546474849
4A4B4C4D4E4F50515253545
5565758595A5B5C5D5E5F60
6162636465666768696A6B6
C6D6E6F7071727374757677
78797A7B7C7D7E7F"
>END
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
TYPE :HCR
END
Then, when you test it by typing PRNT1 32 [RETURN] it responds with:
20
?
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.
PRNT CALL
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