THE ATARI 6502 DISASSEMBLER

Table of  Contents

•	License And Disclaimer
•	Purpose of DIS6502
•	Features of DIS6502
•	Setting Type To Bytes
•	System And User Equates
•	Output Customization
•	Viewing Sprites
•	ATARI-PC File Transfer
•	Using SPY Disk
•	Bug Reports And Comments

License And Disclaimer

License

The Atari 6502 Disassembler, this document and all other portions of the DIS6502 archive not the property of third parties are the copyrighted property of Eric BACHER.

This prgram is a FREEWARE. You are granted permission to give copies of DIS6502 to others, provided that the files in this ZIP file are all included and not modified.

If you like DIS6502 please send me an email letting me know how DIS6502 is working for you.

Disclaimer

The author makes no representations or warranties with respect to the contents hereof and specifically disclaims any implied warranties of merchantability or fitness for any particular purpose. Further, the author reserves the right to revise this publication and to make changes from time to time in the content hereof without obligation of the author to notify any person or organization of such revision or changes.

WARNING: This version may contain some bugs. USE ONLY WITH BACKUP .ATR/.XFD FILES. USE IT AT YOUR OWN RISK! ACCEPT THE RESPONSIBILITY OR DO NOT USE THIS PROGRAM!

Purpose of DIS6502

Atari

The Atari 6502 Disassembler (DIS6502) is a Windows application that lets you interactivly disassemble an Atari binary file that resides on your hard disk or in image disks (.ATR/.XFD). You can then save a -ready to assemble- listing in a file.

DIS6502 has been created in the idea that a disassembly IS NOT a batch process but really AN INTERACTIVE AND ITERATIVE PROCESS !

For exemple, if you see a string in the object file, you should be able to tell the disassembler to put the string in a .BYTE directive avoiding the disassembly of it. Same thing for sprites or display lists.

 DIS6502 is a 16-bit Windows program that runs on Windows 3.1 and Windows 95. I made a 16-bit program so that people that did not upgrade to Windows 95 can also use the disassembler.

Other computers

DIS6502 has been enhanced to disassemble files from other 6502 computers. It supports Oric and 5200 files.

To use DIS6502 for these computers, use a command line option:

Oric Tape files		DIS6502.EXE /Oric
5200 ROM files	DIS6502.EXE /5200

Features of DIS6502

DIS6502 lets you disassemble

•	Atari binary files on your hard disk, 
•	Atari binary files in .ATR/.XFD disk images, 
•	Boot sectors in .ATR/.XFD disk images, 
•	Any part of any sectors in .ATR/.XFD disk images, 
•	Spy data which is explained in "SPY disks" chapter.

A binary file contains one or several segments. A segment is a memory area and is identified by a start address and a length. When you load a binary file into the disassembler, the segment list is displayed into the upper left listbox. When you click on one of these segments, you see the dump in another listbox. This listbox shows all the bytes of the selected segments in hexadecimal and in ASCII/ATASCII format. You have also the disassembly listing on a right listbox.

Once you have loaded, for example, a binary file, DIS6502 offers you full access to its menu:

The different menus are:

•	File, 
•	Select, 
•	Labels, 
•	Tools, 
•	Options, 
•	Help,

Let's review each menu:

File Menu

New clears all the segments loaded in memory.

Open binary file... loads an Atari binary file from your hard disk. This file must have the binary header ($FF $FF) to be recognized.

Open disk image file... loads an Atari binary file from .ATR/.XFD disk images. Only DOS 2.5 disks are supported. The disk can be a single or enhanced density disk.

Open disk image boot... loads boot sectors from .ATR/.XFD disk images. Boot sectors are considered to be 128 bytes long.

Open disk image sectors... loads any part of any sectors from .ATR/.XFD disk images. All densities/sizes are allowed: single, enhanced, double, quad or even larger (hard disk)

Open spy disk image data... loads data captured with a SPY disk.

Save disassembly listing... saves on your hard disk the listing generated by DI6502.

Load workspace... loads your work where you left it when you saved it with "Save workspace...". Without this option, each time you run the program, you start disassembling from scratch. Now you can set byte type, save workspace, and come back later in DIS6502 to continue working on the disassembly.

Save workspace... saves your work on your hard disk so you resume it later. This option does not save Assembler format. You have to do it yourself with another menu.

Exit quits DIS6502. BE CAREFUL: It doesn't ask you to save your work if you didn't do it.

Select Menu

Select all selects all the bytes in the dump window.

Select sprites... lets the user search for the sprites in the selected segment. This dialog box is explained in "Viewing Sprites" chapter.

Find... can be used to find a HEX string or an ASCII string in the dump window. This lets you find the first occurence of a byte pattern in the selected segment or in all the segments.

Find next is used to find next byte pattern. This menu has a short key (F3) to get the next pattern with just one keystroke.

Labels Menu

Clear all deletes all the user labels that you have defined.

Edit... lets you add/delete/modify a label that will be used in the disassembly listing.

Load... loads all the user labels from an ASCII file.

Save... saves all the user labels in an ASCII file that you can edit with NOTEPAD for example.

Tools Menu

Merge segments looks at start and end address of each segment and try to find consecutive segments. If DIS6502 finds 2 consecutive segments, it merges them into a single segment.

Write boot disk... writes the selected segment as boot sectors. DIS6502 asks the user the load address and the init address to be able to write the header of the boot sectors.

Prepare spy disk... writes/modifies information for a SPY session. See "Using SPY Disk" chapter.

Disk image to PC transfer... lets the user extract a file from a disk image or write a file from hard disk to a .ATR/.XFD disk image. See "ATARI-PC File Transfer" chapter.

Options Menu

Sreen display toggles between ASCII and screen (ANTIC) display in the dump window.

No disassembly toggles the start of the disassembly process. If "No disassembly" is checked, the disassembly process only takes place when a binary file is loaded. If this option is not checked (this is the default), disassembly is done each time a byte type is set or each time Assembler format is changed. Checking this menu is usefull when you need to do many changes without being disturbed by the disassembly process.

Output format... lets you choose the number of WORDs per line, the number of BYTEs per line and the number of characters per string.

Assembler format... customizes DIS6502 to meet your assembler syntax. "See Output Customization" chapter.

Help Menu

About... displays version of DIS6502.

Setting Type To Bytes

As we said earlier, DISASSEMBLY is an INTERACTIVE and ITERATIVE PROCESS. This chapter explains how this is achieved by DIS6502.

You can improve the disassembly process by looking at the dump and changing the byte type. Each byte of the object file has an associated type given by DIS6502. At first, all the bytes are considered as CODE so the disassembler tries to disassemble all bytes of the file as if they were code.

You can change the byte type by selecting some bytes in the dump window and clicking with the right button. A popup menu will appear. Choose 'Type' and a sub-menu will appear. Then you can select the new type for the selection.

For exemple load RAMDISK.COM from DOS 2.5 master disk. In the first segment, scroll the dump window until the end. You see a text saying "Setting Up ATARI 130XE Ram Disk". There is no code here. We have to tell DIS6502.

To do this, in the hexadecimal or ASCII part of the dump window, select bytes from address $3B81 to $3BAA then click the right mouse button inside the dump window and choose "String" in the "Type" sub-menu.

NOTE: In this example, we set the type to Bytes but there are many other types supported by DIS6502 that help you get your disassembly listing nicer and also more readable and understandable.

DIS6502 will disassemble again the file but this time the text "Setting Up ATARI 130XE Ram Disk..." appears in .BYTE directives and not as 6502 instructions (AND #$7D, ORA L1D1D,X...).

The different types are:

•	Code, 
•	Code with Low Byte, 
•	Code with High Byte, 
•	Byte, 
•	Word, 
•	Label, 
•	String, 
•	Screen Byte, 
•	Display List, 
•	Data Storage.

Each type is described in the following paragraphs.

Changing the type of one or several bytes is useful to improve the disassembly. You have to look at both the disassembly listing and the dump window. If you see parts of code that mean nothing, then you should look at the dump window to check if it is really 6502 code. You may find that there is a string, a display list, a sprite or anything else. In that case, just select the area and change the byte type to whatever you think it is. These paragraphs explains the different types known by DIS6502.

Code

This byte will be disassembled as code.

Code with Low Byte and Code with High Byte

This type must be applied only on an immediate operand. For example, if you see these bytes in the disassembly:

A9 80 8D 30 02 A9 40 8D
31 02

The disassembler will produce the following listing:

LDA #$80
STA SDLSTL
LDA #$40
STA SDLSTH

When you see this, you know that $80 and $40 are the Low and Hi bytes of an address. So you select 80 in the dump window and set the type to 'Code with Low Byte'.

When you do this, you tell DIS6502 that $80 is the low byte of an address...but which address? That's what DIS6502 asks you when it opens a dialog box. You have to enter the missing byte of the address (40 in our example).

Then you select 40 and set the type to 'Code with High Byte'. DIS6502 opens again its dialog box but this time you have to enter the low byte (80 in our example). After that, the listing will show:

L4080 = $4080
...
LDA # <L4080
STA SDLSTL
LDA # >L4080
STA SDLSTH

Byte and Word

You can set some bytes to Byte or Word type. They will appear in .BYTE or .WORD directives in the listing.

Label

This is used when you know that 2 consecutive bytes are an address. If you want to see it as a label, you set both bytes to Label. It will appear as a .WORD directive with a name instead of an hexadecimal address. This name can be either a system equate or a name generated by the disassembler. For example

30 02 80 40

These 4 bytes are marked as Label. The listing looks like this:

.WORD SDLSTL,L4080

String and Screen Byte

These 2 types are strings. The first one is an ASCII string while the second one is for strings that are used by Antic in the screen memory. Strings appear as .BYTE "hello". Screen bytes appear as .SBYTE "hello" (if this directive is supported by the assembler).

Display List

If you know that some bytes are parts of a display list, you can tell the disassembler. It will produce a readable listing instead of bytes. For example, if you have

70 70 70 47 8B 33 70 46
EF 33 70 70 70 70 70 70
70 42 C7 33 70 46 EF 33
41 70 33

It will produce the following listing:

L3370 .BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE ALMS+$07
.WORD L338B
.BYTE AEMPTY8
.BYTE ALMS+$06
.WORD L33EF
.BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE AEMPTY8
.BYTE ALMS+$02
.WORD L33C7
.BYTE AEMPTY8
.BYTE ALMS+$06
.WORD L33EF
.BYTE AVB+AJMP
.WORD L3370

If you are familiar with display list, you recognize LMS, JMP,... with a 'A' prefix which stands for Antic. AEMPTY8 means 8 empty scan lines. ALMS+$06 means Load Memory for Antic mode 6. AEMPTY8, ALMS, AJMP and AVB are predefined labels in ATARI.EQU file.

Data Storage

Data Storage is used to skip bytes in memory. If you see a bunch of .BYTE $00 and you know that it is an uninitialized area that the disassembler has translated into .BYTE directive, then you can set the type of all these bytes to Data Storage. A single .DS directive with the number of bytes skipped will appear in the disassembly listing.

System And User Equates

System Equates

All known OS and Hardware equates are defined in a file called ATARI.EQU. This file contains all the system equates that DIS6502 may need when disassembling a binary file. This file has a special format so DIS6502 knows for each equates if it is an address or a value. DIS6502 has to know it since an address equate can be used in an instruction like LDA or JMP while a value equate can not.

Use '=' to define an address and '#' to define a value.

Syntax example follows:

ICAX1 # $0A
ICAX2 # $0B
PCOLR0 = $02C0
PCOLR1 = $02C1

ATARI.EQU should contain only program independant equates. If you need to define equates for a specific binary file, you should do it with the Labels menu because those labels are User Equates.

User Equates

The Label menu lets you clear, define, load and save equates on a per binary file basis. You can have many user equate files (for example one for each program you are disassembling).

In our RAMDISK.COM example, we see that address $3B5D is the start address of the program because this address appears in the second segment at address $02E0.

Select "Edit..." option from "Labels" menu. A dialog box appears. At this time, there is no labels defined. Enter 3B5D in Addr field and START in Label field and click on Add/Modify button. Then select OK.

Now, each time the address 3B5D appears in the listing, DIS6502 replaces it by its corresponding label START.

You can define a label with an offset. For example, if you see that address 3B5E is referenced in the disassembly listing, you could either define another label like BEGIN or use START with an offset. In the previous dialog box, enter 3B5E in Addr field and START+1 in label field.

This will tell DIS6502 to replace all addresses 3B5E by START+1 but DIS6502 won't define this label because it can not write START+1 = $3B5E in the disassembly listing. Only START should be defined. DIS6502 expects that you define START just as we did previously.

Output Customization

The disassembler is compatible with MAC/65 and it's highly customizable. In the Options menu, choose Assembler format option. It will open a dialog box where you can customize the disassembler to meet your assembler syntax.

When you have entered all the parameters for your assembler, you can save them into a .PRF file. This chapter explains all the fields of the dialog box.
You can load the .PRF file corresponding to your assembler by clicking on the Load profile button.

Three .PRF files are given:

•	MAC/65, 
•	Assembler/Editor cartridge, 
•	LADS.

LADS is an assembler that does not support many directives. It does not support .WORD and .SBYTE, does not want labels or equates in .BYTE, uses space as value separator in .BYTE,...In fact, it was very good to see if the disassembler could be customized !

If you want DIS6502 to load your profile automatically, save your settings in a file called ATARI.PRF, ORIC.PRF or 5200.PRF depending on computer mode. On startup, DIS6502 tries to load this file.

NOTE: If you use any other assembler and make a .PRF for it, please send it to my email address shown in the About box of the disassembler.

When you open the 'Assembler format' dialog box, you see 3 sections called:

•	General, 
•	Directive syntax, 
•	Include files.

The fields of these 3 sections are explained below:

General section

•	Comment 

The only comments added to the listing are full line comments (no comments after an instruction for exemple). You can define here the string for a comment.

Default: ;

•	Hex prefix 

String identifying an hexadecimal value.

Default: $

•	Illegal instructions 

If your assembler supports all illegal instructions, you can check this option. The disassembler will disassemble all the illegal instructions and will write them in lowercase so you can recognize them in the listing.

Default: OFF

•	Line numbering 

Used to know if the disassembler should generate line numbers.

Default: OFF

Note: MAC/65 uses line numbering but I set the default to OFF because you can use the ENTER #D:filename.ASM,A option to load the source and add line numbers at loading time.

•	Align instructions 

This option is used to align instructions.

If it's ON, you will have something like that:

If it's OFF, the listing will show

Default: ON

•	Use hex notation 

All values are displayed as hex numbers if this option is set to ON. Otherwise, everything is displayed in decimal.

Default: ON

•	Display 'A' in Accumulator mode 

Some assemblers like 'LADS' do not support an operand for accumulator mode. For example: LSR A generates a syntax error with LADS. The disassembler should generate LSR instead of LSR A.

Default: ON

Directive syntax section

•	Numbers only in .BYTE 

If your assembler does not support labels or equates in .BYTE directive, you have to check this option. When turned OFF, the assembler can generate the following lines:

.WORD L33EF
.BYTE AEMPTY8

If this option is turned ON, the disassembler will generate

.BYTE $EF,$33,$70

Default: OFF

•	.WORD allowed 

If your assembler has a directive to reserve space for a WORD, you should check this option and enter the syntax for it.

Default: ON and .WORD

•	.BYTE 

This option must exist in your assembler...but with another name. So you can enter the name of your directive to reserve one byte.

Default: .BYTE

•	Sep 

When putting several bytes in a .BYTE directive, the disassembler must know which separator to use between the bytes.

Default: ,

•	.SBYTE allowed 

If your assembler has an option that let you enter string of text with Screen (or Antic) codes, you should check this option and enter the directive syntax.

Default: ON and .SBYTE

•	.ORG 

Enter the directive to set the program counter.

Default: *=

•	Low byte 

This option defines the syntax used for the type 'Code with Low byte'. The disassembler must know how to extract the low byte from a word (or from a label). In MAC/65, '<LABEL' is used. In the Assembler/Editor cartridge, you have to mask the high byte with 'LABEL&$00FF'. Another assembler might use a syntax like 'LOBYTE(LABEL)'. To support varied syntax, you have 2 fields in this option. The first one is the string that will appear BEFORE the address (or label). The second one is the string that will appear AFTER the address (or label). Here are 3 examples:

MAC/65: LDA # <L33EF

Asm/Ed: LDA #L33EF&$00FF

Other assembler: LDA #LOBYTE(L33EF)

Default: <

•	High byte 

Same as Low byte !

Default: >

•	EQU 

This is the syntax to define an equate.

Default: =

•	.END 

This is the complete syntax to end a disassembly listing. Enter the name of the directive for your assembler. Some assemblers need the name of the source file name after this directive: .END D:TEST.ASM In this case, you should check the 'Add filename' checkbox.

Default: .END

•	.DS allowed 

If your assembler has a directive to reserve space for uninitialized data, you should check this option and enter the syntax for it.

Default: ON and .DS

Include files section

•	.INCLUDE 

This option defines the syntax used to include a file. This becomes important when you have a large source file. In this case, you split the file into several ones and link them with this directive. To support all the syntaxes for this directive, you have 2 fields in this option. The first one is the string that will appear BEFORE the filename. The second one is the string that will appear AFTER the filename.

Default: .INCLUDE #

•	Number of lines per include file. 

You can set the maximum number of source lines to put in a source file. This is to prevent the disassembler from generating large source files that your editor can not load into memory.

Default: 500

•	Inclusion method 

There are 2 ways for including files.
The first one makes a main source file that includes all other files.

The second one is to include the next file at the end of each source file. Click on the method that your assembler accepts.

Default: All files included in 1 main file

•	Include files allowed. 

Click this check box if your assembler supports include files AND if you wish to generate multiple files for your source.

Default: ON

Viewing Sprites

Sometimes, you see that the disassembly listing is unreadable because there are some bytes that are not code but you do not know what it is. And you know that you are disassembling a game so there should be sprites or pictures inside the file! To view them, you can choose 'Select sprite' option in the Tools menu. It opens a dialog box and display the current segment datas as a bitmap.

Sprites from PACMAN

The horizontal scroll bar is used to set the width of the sprite. It means that if a sprite is 8 pixels wide in Antic mode A (80x48 with 4 colors), it takes 2 bytes per line. You set the horizontal scroll bar to 2 and you will see the sprite.

The vertical scroll bar is used to browse through the segment. The address of the upper left pixel is displayed as the Start address. If you click in the window, you will be able to select an area from Start to the point where you have clicked. If you select OK, the dialog box will close but the dump listbox will show the selection that you made in the 'Select sprite' dialog box. You just have to change the type of the selection to Byte to notify the disassembler that this part contains no code but .BYTE data.

ATARI-PC File Transfer

This option is used to transfer files from Disk image (.ATR/.XFD) to PC and the contrary. This is useful when you save a listing on your hard disk, modify it and then want to compile it on your Atari (or with an emulator). Then you must transfer your source file to a .ATR disk image.

NOTE: There are 3 limitations:

•	it supports only SINGLE density .ATR/.XFD images 
•	it supports only the DOS 2.5 file system 
•	it does not erase/replace files in .ATR/.XFD. You have to delete files with a real Atari, an emulator or another utility. It can only create new files.

Using SPY Disk

When you disassemble a boot disk (BOOTGAME.ATR for example), sometimes, you will see that only a small part of the code is readable and the rest is crypted. Usually the readable part contains a loop to modify the rest of the code. It is used to prevent people from disassembling the code. The simplest algorithm is to EOR all the crypted code with a value.

To be able to disassemble that kind of code, the best way would be to run the small part that transforms crypted code to readable (and executable) code and disassemble it after.

This is what SPY disks can do for you.

•	First, you need to look at boot disk code to understand what it does. When you see where the algorithm that decrypts the code is, you determine an address where SPY can set a breakpoint. You should select an address where the program goes after the decryption algorithm has been applied. You also need to remember the area where the new code has been decrypted.

•	Select 'Prepare spy disk'. A dialog box appears. Enter the breakpoint address in the upper left field called 'Patch addr'. This is the address where the code will be modified so SPY program can get control back. In fact, it overwrites the code to put a JMP instruction that points to SPY code. After, enter the address and the length of the area that will be decrypted by the program itself. It will be saved by SPY program on disk so you can examine it later. Press Add button to add this area to the 'Memory areas to save on spy disk' listbox.

•	You can enter a name for your SPY disk that will appear on screen when you run the SPY program. You can also check the 'Continue execution of boot disk after last patch' option if you want to check that the patch did not destroy anything in memory. This is very useful to check that the program works well even if it has been 'patched'. This way, you are sure that the decrypt algorithm that has been applied is the good one and that it works the normal way because you see the program running. This option lets you check that the SPY program did not disturb the normal execution of the boot disk.

•	Save the spy data into a fresh disk with the 'Save spy...' button. This disk will contain the spy data and the results. We will call it SPYDATA.ATR for example. Note that you have to copy another .ATR to SPYDATA.ATR before saving you work because the 'Save spy...' button will not create a new .ATR file. It will only overwrite an existing one.

At this point, you have

•	BOOTGAME.ATR that you want to disassemble, 
•	SPYDATA.ATR: a SPY disk that you have just customized.

Now, you need to select one of the several SPY programs that will run in your Atari. It is the same program but assembled at different addresses. You have to look at the code of the boot disk and choose a memory location that is not used by the code. The possible addresses are $1000, $3000, $5000, $7000, $9000 and $B000. They are provided as boot disk under the name SPYxxxx.ATR where xxxx is one of the address (SPY1000.ATR for SPY program that runs at $1000).

Now you should have 3 disks (.ATR files):

•	BOOTGAME.ATR that you want to disassemble 
•	SPYDATA.ATR: a SPY disk that you have just customize. 
•	SPYxxxx.ATR: the SPY program that loads and runs at $xxxx.

Follow theses steps:

•	With SIO2PC or APE for example, load SPYxxxx.ATR
•	Turn on your Atari.
•	When the program is booted, it should display
Insert spy disk in D1: and press START.
•	Remove SPYxxxx.ATR and load SPYDATA.ATR then press START.
•	When the data are loaded, it should display
Insert boot disk in D1: and press START.
•	Under APE, remove SPYDATA.ATR and load BOOTGAME.ATR then press START.
•	The disk will boot the normal way and when the program finds the JMP patch, it will return in the SPY program. Then it should display
Insert spy disk in D1: and press START.
•	Remove BOOTGAME.ATR and load SPYDATA.ATR then press START.
•	The SPY prgram will save the memory you want to see on the SPYDATA disk. All is finished execpt if you have checked the 'Continue execution of boot disk after last patch' option. In this case, it should display
Insert boot disk in D1: and press START.
•	The program should continue the normal way. You should be able to play the game or use the software.

You now have a SPYDATA.ATR where some part of the memory has been saved. To examine the results, you have to run the 6502 disassembler for Atari. In the File menu, choose 'Open spy disk image data...'. Choose SPYDATA.ATR Now, if everything goes fine, you should be able to see the code that was previously crypted !

There are some disks that are heavily protected and that run a first decrypt code, then a second, then a third,...

In this case, you have to repeat the previous operations untill all the code is readable.
For example if you have some code at address $4000 that unprotects code from $4100 to $5000 and after, code at $4100 unprotects code from $4200 to $5000.

•	You must enter a first patch address of $40F0 for example and try the patch. Looking at the result, you see that there is still a part from $4200 to $5000 that is unreadable.
•	You must edit again the SPYDATA.ATR disk and ADD (do not remove the first patch !!!) a new patch address of $41F0 for example. The second try will reveal all the code from $4200 to $5000.

In many cases, you won't have to do that but look at the following code:

START
LDY #0
DECOD 
LDA CRYPT,Y
EOR $80,Y
STA CRYPT,Y
STA $80,Y
INY
BNE DECOD
CRYPT 
.BYTE $40,$23,$B6,$93
...

This code decrypts 256 bytes at label CRYPT. To use the SPY program to reveal the code, you need to select an address for the patch:

•	You can not put the patch AFTER the CRYPT label because it is the part that will be modified !
•	You can not put the patch BEFORE the CRYPT label because it will jump back into SPY program when only one byte (the first at label CRYPT) has been unprotected.

You can not use the normal SPY program to reveal this kind of code because you don't know where to put the patch (JMP instruction to get back to SPY program). You need to edit SPY.M65 and customize it for one particular case.

When you edit SPY.M65, you see a big comment like this one:

;
; User patch.
; -----------
; This part of code is
; executed when a patch
; address is 0. It means
; either that there is no
; more patch or the user
; has put a 0 address to
; do a special task
; between several patches.
;
; At this time, we have
; restored program code
; (no patch), saved
; program registers into
; SAVEREGS and CURPATCH
; points to a 0 address.
;
; We can modify this
; patch so it will do
; something, then JMP to
; USERPATCH or just INC
; twice CURPATCH to get
; to the next patch and
; JMP to USERPATCH.
;
; If nothing has to be
; done, then a JMP to
; USEREND will continue
; the normal operations.
; It will ask for the
; SPY disk to save datas.
;
; LASTPATCH is the address
; where we left off the
; program execution.
;
USERCONTROL
JMP USEREND

You don't need to look at the file SPYCORE.M65 that does the dirty work of applying the patch, removing the old one, saving memory to SPYDATA.ATR, and many other things...

What you need to know is that code at label USERCONTROL is executed when there are no more patches (it means that all the patches in the list have been applied or that the patch list was empty). Here, you can put your own code to do something. When your code has finished its work, it can call JMP USEREND to continue normal SPY program execution. The SPY program will then ask for the SPY disk and save the memory areas on disk.

What can we do here ? If we continue with our exemple, we could set a patch address at label START (LDY #0). Then type in the small piece of code that unprotects the 256 bytes:

USERCONTROL
LDY #0
DECOD2 
LDA CRYPT,Y
EOR $80,Y
STA CRYPT,Y
STA $80,Y
INY
BNE DECOD2
JMP USEREND

This code will execute when there will be no more patch. When the SPY program boots, it asks for the SPY data disk. When you press the START key, the spy data are loaded. It then asks for the boot disk. When you press the Start key again, it loads the boot sectors as if the Atari has just been turned on. Then it applies the first patch and jumps to the init address of the boot disk. When the code patch (JMP instruction) is executed, it returns the control to the SPY program. The SPY program remove the first patch and search for the next patch. It sees that there is no more patch (patch address is $0000) so it jumps to the USERCONTROL label. Here, the code that we added unprotects the 256 bytes. Then we jump to USEREND to resume execution of the SPY program which prompts the user for the SPY data disk to save memory.

You have to assemble the source at the desired address (for example $3000. Then you have to use 6502 Disassembler for Atari to convert your SPY3000.COM file to a boot disk (SPY3000.ATR).

If you see another part of the code that is protected, it means that you have to do 2 patches, the first one is the code that you customized in SPY.M65. If the second patch can be applied the normal way (without modificatins to SPY.M65), you should do it this way:

•	Add a patch address of $0000 (after the patch address at label START), then the patch address for your second patch ($41F0 for example). The patch address of $0000 tells SPY program to not apply a patch in boot disk but to jump to USERCONTROL. The listbox should display

40F0 (the START label for example)
0000
41F0

•	Modify SPY.M65 to execute the code only the first time. If you do not change anything, the code at label USERCONTROL will execute twice. One time because of the patch address of $0000 and one time after the last patch (in fact, this is because the end of the patch list is seen as a patch with address $0000).

USERCONTROL
;
; Is it Patch number 1
;
LDA CURPATCH
LSR A
CMP #1
BEQ PATCH1
JMP USEREND
;
; Do patch 1
;
PATCH1 
LDY #0
DECOD2 
LDA CRYPT,Y
EOR $80,Y
STA CRYPT,Y
STA $80,Y
INY
BNE DECOD2
;
; There is another patch to
; apply so we need to setup
; CURPATCH to point to the
; next patch (patch 2) and
; set the next address to
; run (in boot disk code)
; just after the decrypt
; code.
;
INC CURPATCH
INC CURPATCH
LDA # <CRYPT
STA LASTPATCH
LDA # >CRYPT
STA LASTPATCH+1
JMP USEREND

Again, you have to assemble the source at the desired address (for example $3000. Then you have to use 6502 Disassembler for Atari to convert your SPY3000.COM file to a boot disk (SPY3000.ATR).

The test CMP #1 prevents the code at label PATCH1 to be executed twice.

Bug Reports And Comments

Feel free to send me any comments or new ideas. I will be happy to help you if you have any trouble using the disassember. If you find a bug, please send a detailed description to:

Eric BACHER (mailto:ebacher@compuserve.com)

Many thanks to all the people who helped me find problems in the previous version. I hope they will continue to support my work. Special thanks to:

•	Steven J. Tucker 
•	Kurt Mosiejczuk 
•	R. Wayne Arenz 
•	Raul Andres Santelices Ahues