ATARI
Memory Dump and Dissassembler
Robert. W. Baker Atoo, New Jersey
Here's a handy little utility program for the Atari 400/800 systems. It lets you examine any area of memory, either RAM or ROM, in one of two formats. You can select whether you want a straight memory dump or a dissassembly listing. In both formats, the memory locations are given as both decimal and hexadecimal values. The data can be displayed on the television/monitor screen or printed on a printer if available.
When first run, the program takes a minute or two to initialize but from then on it is relatively fast. The starting address for the dump/dissassembly can be entered as either a decimal or hexadecimal number. When entering it as a hexadecimal number, precede the number by a dollar sign ($). You're then asked if a dissassembly is desired. Answering N for no will cause the standard memory dump to be displayed. Answering Y for yes will generate the dissassembly listing.
Before the dump/dissassembly is displayed you are given the option to have the output printed if desired. Answering N for no causes the output to be displayed as normal, using the entire display (24 lines). At the end of each screen you are given the option to continue (C), restart (R), or stop (S). Continue will display the next screen in sequential order. Restarting will return to select the starting address and allow specifying dump/dissassembly and printer options. When printing the data output, the printer will print continuously. Just press any key on the Atari keyboard to halt the printer. When the printer stops you will see the prompt for continue, restart, or stop as mentioned above.
Memory Dump
The memory dump simply displays the contents of eight bytes of memory on each line displayed or printed. The values are given in hexadecimal to conserve display space and to correspond with the dissassembly listings. This feature is very useful for examining pointers or various values stored in memory, that do not happen to be executable machine code instructions. You might want to play around with looking at how BASIC variables or even BASIC lines themselves are stored in memory on the Atari.
For those with 80 column printers (Atari 825, etc.) you can change the FOR-NEXT loop count in line 600 to get 16 bytes per line to conserve paper. Just change line 600 to:
FOR X = 1 TO 16 : V = PEEK(A)
You might even want to change the heading line in line number 302 to print the numbers 0 to 9 plus A to F.
Dissassembly Listing
This feature is much more powerful and can provide a wealth of information. When a dissassembly is requested, the program displays one 6502 machine instruction per line. It indicates the hexadecimal value of one to three bytes of memory that make up the instruction. It also displays the instruction and operand in the standard assembly code forms.
Any unrecognized values are indicated by a "*?*" instead of an instruction mnemonic. You may have to try different starting locations to get the dissassembly to function properly. If you specify an address that happens to be the middle of an instruction, it may dissassemble as a different instruction and/or cause following instructions to be displayed incorrectly. This is always a problem with a dissassembly program of this kind. It is extremely difficult to "sync-up" with the machine instructions whenever there are data bytes between various routines, etc. If you should see a high number of *?*'s displayed, try another starting address, possibly one to two higher or lower than the original address. This should correct the situation.
The dissassembly gives each instruction using standard MOS Technology mnemonics and addressing nomenclatures. Operand values and addresses are shown in hexadecimal and are prefixed by a dollar sign ($) as a reminder. All immediate values are preceded by parenthesis and indexed values are suffixed by a ",X" or ",Y" as appropriate. Zero page addressing is implied by the length of the operand being only a single byte. All branch instructions show the actual computed target address in the dissassembly for added convenience. If required, the relative offset is shown in the object code.
The dissassembly function is extremely useful for examining machine language routines such as those used within the BASIC cartridge itself, or in the operating system ROMs. I'll let you know if I come across anything interesting hidden in the Atari system. Before anyone asks — if you'd like a copy on cassette tape instead of doing all the typing, send $2 to cover costs.
Just a quick note concerning the program listings. The heading lines printed by the BASIC statements in lines 302 and 305 were actually in reverse image to enhance the display. Unfortunately this does not show up in the program listings. I have tried to use CHR$(xx) functions in the print statements for clearing the display, etc. to make things easier to read. The Atari printers do not print the graphics and/or control characters that can be included in PRINT statements. Actually they can cause problems if a program is LISTed with these control characters imbedded in PRINT statements. The control characters will be decoded and acted upon by the printer.
10 REM ****************************** 20 REM 25 REM MEMORY DUMP/DISASSEMBLER 30 REM 35 REM BY : ROBERT W. BAKER 40 REM 15 WINDSOR DR, ATCO NJ 08004 50 REM 60 REM ***** V1.0 ******* 1/4/81 **** 65 REM 70 GRAPHICS 0 : POKE 752, 1 80 PRINT CHR$ (125) ;" M E M O R Y D U M P " : ? : ? 90 PRINT "INITIALIZING ....." 100 DIM H$(16), A$(6), S$(6), M$(1536) 110 H$ = "0123456789ABCDEF" 120 S$ = " " 150 OPEN #1, 4, 0, "K" 160 FOR X = 1 TO 1531 STEP 6 170 READ A$ 175 IF A$(2, 2) = "*" THEN A$(2, 4) = "*?*" 180 N = LEN(A$) : IF N < 6 THEN A$(N + 1) = S$ 185 M$(X, X + 5) = A$ : NEXT X 200 PRINT CHR$(125) ; "M E M O R Y D U M P" : ? : ? 201 PRINT "ENTER DECIMAL STARTING ADDRESS" : PRINT 202 PRINT "OR HEX ADDRESS PRECEDED BY ‘$’" : PRINT 203 POKE 752, 0 204 INPUT A$ : IF A$ = " " THEN 800 205 IF A$(1, 1) = "$" THEN 209 206 FOR X = 1 TO LEN(A$) 207 IF A$(X, XX "0" OR A$(X, X) > "9" THEN 200 208 NEXT X : A = INT(VAL(A$)/8) * 8 : GOTO 240 209 A = 0 : IF LEN(A$) < 2 THEN 200 210 FOR X = 2 TO LEN(A$) 211 IF A$(X, X) < "0" THEN 200 212 IF A$(X, X) < = "9" THEN A = A * 16 + VAL(A$(X, X)) : GOTO 220 215 IF A$(X, X) < "A" OR A$(X, X) > "F" THEN 200 218 A = A * 16 + ASC(A$(X, X)) - 55 220 NEXT X 240 PRINT : PRINT "WANT DISSASSEMBLY (Y/N)?" ; 242 GET #1, X : D = 0 : IF X = 78 THEN 245 244 D = 1 : IF X<> 89 THEN 240 245 PRINT CHR$(X) 250 PRINT : PRINT "WANT PRINTED COPY (Y/N) ?" ; 252 CLOSE #2 255 P = 0 : GET #1, X 260 IF X = 78 THEN OPEN #2, 8, 0, "E" : GOTO 290 270 IF X<>89 THEN 255 280 P = 1 : OPEN #2, 8, 0, "P" 290 IF P = 0 THEN PRINT CHR$(125); : GOTO 300 295 PRINT CHR$(125) ; "DEPRESS ANY KEY TO HALT PRINTER" : PRINT #2 300 PRINT #2 ; "LOC - DEC/HEX" ; 302 IF D = 0 THEN PRINT #2 ; "0 1 2 3 4 5 6 7" : GOTO 310 305 PRINT #2 ; "OBJECT DISSASSEMBLY" 310 PRINT #2 320 POKE 764, 255 330 IF P = 0 THEN FOR N = 1 TO 20 340 IF A > 65535 THEN A = A - 65536 350 A$ = STR$(A) : L = LEN(A$) 360 PRINT #2 ; S$(1, 6-L) ; A$ ; " " ; 370 Y = A : GOSUB 950 380 PRINT #2 ; " : " ; 400 IF D = 0 THEN 600 410 V = PEEK(A) 411 GOSUB 1000 : PRINT #2 ; " " ; 415 A = A + 1 : X = (6 * V) + 1 : A$ = M$(X, X + 5) 420 IF A$(1, 1) = "0" THEN PRINT #2 ;"" ; A$(2, 4) : GOTO 630 430 V = PEEK(A) : GOSUB 1000 432 PRINT #2 ; " " : A = A + 1 435 IF A$(1, 1) = "2" THEN 500 440 PRINT #2; " " ; A$(2, 4) ; " " ; 445 IF A$(5, 5)<> "R" THEN 470 450 IF V > 127 THEN V = V - 256 460 Y = A + V : GOSUB 900 : GOTO 590 470 IF A$(5, 5) = "#" THEN PRINT #2 ; "#$" ; : GOSUB 1000 : GOTO 590 475 IF A$(6, 6) =")" THEN PRINT #2; "(" ; 480 PRINT #2 ; "$" ; : GOSUB 1000 482 IF A$(5, 5) = " " THEN 590 485 IF A$(5, 6) = "Y)" THEN PRINT #2 ; "), Y" : GOTO 630 490 PRINT #2 ; "," ; A$(5, 6) : GOTO 630 500 V1 = V : V = PEEK < (A) : GOSUB 1000 : A = A + 1 510 PRINT #2 ; " " ; A$(2, 4) ; " " ; 515 Y = V1 + (256 * V) 520 IF A$(5, 5) = ")" THEN PRINT #2 ; "(" ; : GOSUB 900 : PRINT #2 ; ")" : GOTO 630 525 GOSUB 900 530 IF A$(5, 5) = " " THEN 590 540 PRINT #2 ; "," ; A$(5, 5) : GOTO 630 590 PRINT #2 : GOTO 630 600 FOR X = 1 TO 8 : V = PEEK(A) 610 GOSUB 1000 : PRINT #2; " " ; 620 A = A + 1 : NEXT X : PRINT #2 630 IF P = 0 THEN NEXT N : GOTO 700 640 IF PEEK (764) = 255 THEN 340650 GET #1, X 700 POKE 752, 1 : PRINT 705 PRINT "CONTINUE, RESTART, OR STOP (C, R, S) ?"; 710 GET #1, X : IF X = 67 THEN 290 730 IF X = 82 THEN 200 740 IF X <> 83 THEN 710 800 POKE 752, 0 : CLOSE #1 : CLOSE #2 : END 900 PRINT #2 ; "$"; 950 V = INT (Y/256) : GOSUB 1000 960 V = Y - (V * 256) 1000 H = INT (V/16) : L = V - (H * 16) 1010 PRINT #2; H$(H + 1, H + 1) ; H$(L + 1, L + 1); 1020 RETURN 9000 DATA 0BRK, 1ORAX), 0*, 0*, 0*, 1ORA, 1ASL, 0* 9010 DATA 0PHP, 1ORA#, 0ASL, 0*, 0*, 2ORA, 2ASL, 0* 9020 DATA 1BPLR, 10RAY), 0*, 0*, 0*, 1ORAX, 1ASLX, 0* 9030 DATA 0CLC, 2ORAY, 0*, 0*, 0*, 2ORAX, 2ASLX, 0* 9040 DATA 2JSR, 1ANDX), 0*, 0*, 1BIT, 1AND, 1ROL, 0* 9050 DATA 0PLP, 1AND#, 0ROL, 0*, 2BIT, 2AND, 2ROL, 0* 9060 DATA 1BMIR, 1ANDY), 0*, 0*, 0*, 1ANDX, 1ROLX, 0* 9070 DATA 0SEC, 2ANDY, 0*, 0*, 0*, 2ANDX, 2ROLX, 0* 9080 DATA 0RTI, 1EORX), 0*, 0*, 0*, 1EOR, 1LSR, 0* 9090 DATA 0PHA, lE0R#, 0LSR, 0*, 2JMP, 2EOR, 2LSR, 0* 9100 DATA 1BVCR, 1EORY), 0*, 0*, 0*, 1EORX, 1LSRX, 0* 9110 DATA 0CLI, 2EORY, 0*, 0*, 0*, 2EORX, 2LSRX, 0* 9120 DATA 0RTS, 1ADCX), 0*, 0*, 0*, 1ADC, 1ROR, 0* 9130 DATA 0PLA, 1ADC#, 0ROR, 0*, 2JMP), 2ADC, 2ROR, 0* 9140 DATA 1BVSR, 1ADCY), 0*, 0*, 0*, 1ADCX, 1RORX, 0* 9150 DATA 0SEI, 2ADCY, 0*, 0*, 0*, 2ADCX, 2RORX, 0* 9160 DATA 0*, 1STAX), 0*, 0*, 1STY, 1STA, 1STX, 0* 9170 DATA 0DEY, 0*, 0TXA, 0*, 2STY, 2STA, 2STX, 0* 9180 DATA 1BCCR, 1STAY), 0*, 0*, 1STYX, 1STAX, 1STXY, 0* 9190 DATA 0TYA, 2STAY, 0TXS, 0*, 0*, 2STAX, 0*, 0* 9200 DATA 1LDY#, 1LDAX), 1LDX#, 0*, 1LDY, 1LDA, 1LDX, 0* 9210 DATA 0TAY, 1LDA#, 0TAX, 0*, 2LDY, 2LDA, 2LDX, 0* 9220 DATA 1BCSR, 1LDAY), 0*, 0*, 1LDYX, 1LDAX, 1LDXY, 0* 9230 DATA 0CLV, 2LDAY, 0TSX, 0*, 2LDYX, 2LDAX, 2LDXY, 0* 9240 DATA 1CPY#, 1CMPX), 0*, 0*, 1CPY, 1CMP, 1DEC, 0* 9250 DATA 0INY, 1CMP#, 0DEX, 0*, 2CPY, 2CMP, 2DEC, 0* 9260 DATA 1BNER, 1CMPY), 0*, 0*, 0*, 1CMPX, 1DECX, 0* 9270 DATA 0CLD, 2CMPY, 0*, 0*, 0*, 2CMPX, 2DECX, 0* 9280 DATA 1CPX#, 1SBCX), 0*, 0*, 1CPX, 1SBC, 1INC, 0* 9290 DATA 0INX, 1SBC#, 0NOP, 0*, 2CPX, 2SBC, 2INC, 0* 9300 DATA 1BEQR, 1SBCY), 0*, 0*, 0*, 1SBCX, 1INCX, 0* 9310 DATA 0SED, 2SBCY, 0*, 0*, 0*, 2SBCX, 2INCX, 0*
LOC-DEC/HEX 0 1 2 3 4 5 6 7 40992 A020: 95 00 E8 94 00 E8 E0 92 41000 A028: 90 F6 A2 86 A0 01 20 7F 41008 A030: A8 A2 8C A0 03 20 7F A8 41016 A038: A9 00 A8 91 84 91 8A C8 41024 A040: A9 80 91 8A C8 A9 03 91 41032 A048: 8A A9 0A 85 C9 20 F8 B8 41040 A050: 20 41 BD 20 72 BD A5 92 41048 A058: F0 03 20 99 BD 20 57 BD 41056 A060: A5 CA D0 9C A2 FF 9A 20 41064 A068: 51 DA A9 5D 85 C2 20 92 41072 A070: BA 20 F4 A9 D0 EA A9 00 41080 A078: 85 F2 85 9F 85 94 85 A6 41088 A080: 85 B3 85 B0 85 B1 A5 84 41096 A088: 85 AD A5 85 85 AE 20 A1 41104 A090: 0B 20 9F A1 20 C8 A2 A5 **** SAMPLE MEMORY DUMP *****
LOC-DEC/HEX OBJECT DISSASSEMBLY 40992 A020: 95 00 STA $00, X 40994 A022: E8 INX 40995 A023: 94 00 STY $00, X 40997 A025: E8 INX 40998 A026: E0 92 CPX #$92 41000 A028: 90 F6 BCC $A020 41002 A02A: A2 86 LDX #$86 41004 A02C: A0 01 LDY #$01 41006 A02E: 20 7F A8 JSR $A87F 41009 A031: A2 8C LDX #$8C 41011 A033: A0 03 LDY #$03 41013 A035: 20 7F A8 JSR $A87F 41016 A038: A9 00 LDA #$00 41018 A03A: A8 TAY 41019 A03B: 91 84 STA ($84), Y 41021 A03D: 91 8A STA ($8A), Y 41023 A03F: C8 INY 41024 A040: A9 80 LDA #$8041026 A042 : 91 8A STA ($8A), Y 41028 A044 : C8 INY 41029 A045 : A9 03 LDA #$03 41031 A047 : 91 8A STA ($8A), Y 41033 A049 : A9 0A LDA #$0A 41035 A04B : 85 C9 STA $C9 41037 A04D : 20 F8 B8 JSR $B8F8 41040 A050 : 20 41 BD JSR $BD41 41043 A053 : 20 72 BD JSR $BD72 41046 A056 : A5 92 LDA $92 41048 A058 : F0 03 BEQ $A05D 41050 A05A : 20 99 BD JSR $BD99 41053 A05D : 20 57 BD JSR $BD57 41056 A060 : A5 CA LDA $CA 41058 A062 : D0 9C BNE $A000 41060 A064 : A2 FF LDX #$FF 41062 A066 : 9A TXS ***** SAMPLE DISASSEMBLY *****