- DEBUGGER -
- GENERAL INFORMATION -

Filenames default to the current drive number which can be changed.
(input of 'FILE' = 'D1:FILE') A full filespec will override the default.

Non destructive prompt character (.) for ease in full screen editing.
Also, the prompt does not interfere with command decoding.  If the cursor
is moved up to redo a prior command, the '.' does not need to be deleted.

Upper and Lower case accepted.

The debugger is ZP clean, so all of ZP is available for the user.

You can look at RAM under the OS, by resetting the bit in $D301, as long
as you are using SpartaDOS or some method of handling interrupts when
the OS is disabled.

The debugger uses the E: handler, which can allow two screen debugging
with some 80 column devices.  (Your program is displayed through the Atari,
while debugging output is on the 80 column device.)  Currently, the XEP80
does not work very well in this manner, because its screen drivers require
the Atari DMA to be turned off.  You can partially support this by adding
an external user function to toggle DMA.  More information about this will
be given in a later section.  For machines without an 80 column device, the
debugger supports flipping between two display lists, one for the E:
screen, and one for your program.  In all cases, there can be potential
conflicts when trying to debug programs that use the E: handler themselves,
as both the debugger and your program struggle for the same locations.  The
debugger's design is admittedly not ideal for use in this situation, but it
works out well for programs that create their own screen.

Any continuous displays can be paused and stepped one line at a time with
the space bar.  Press 'C' to return to continuous display.  ESC, RETURN, or
BREAK will stop the display.  While the display is paused, the V command
for switching view screens, and also the U user function, can both be used.

ALL addresses and data bytes can be entered in HEX (default), in DECIMAL
with # (#1234), in BINARY with % (%10011010), in ASCII with ' ('A) or as a
label currently defined in the MAE symbol table with . (.LABEL).
Arithmetic operators +-*/&!\^  can also be used, and will be performed
left to right.  Any combination of these can be mixed at any time in a
completely free format scheme, with no limits on length.
(Ex: 2000-#256+'W/100)  Very little will be mentioned about this feature
later on, but ALL numbers for ALL commands accept this versatile entry
system.

All commands use spaces as delimiters.  A '?' indicates a command error.
Parameter uses for commands are abbreviated to:

adr:  a 16 bit address.
by:   an 8 bit byte. ('by' with numbers indicates a string of bytes.)
bit:  a 0 or a 1.
char: an ASCII character.

Quantities in [brackets] are optional parameters.  Default values will be
used if they are not entered.  All non-bracketted values must be entered.
Any other upper case characters or symbols should be entered as stated.

'Current address' refers to the last displayed or changed address, (+$1),
and is separate from the current program counter or PC.

- COMMANDS -

          Display Memory.     M[M] [adr] [adr][/]
Displays 8 bytes of hex and ASCII when using M, or 16 bytes of ASCII only
when using MM.  Displays 3 lines worth if you enter only one address,
otherwise it will display up to the second address, if entered.  Displays
from current address if no parameters.  '/' = to $FFFF.  The '/' can be
used on all other commands as well.  Does not display ASCII control
characters when output is being sent to an external device.

The hex bytes in the hex and ASCII display (but not the ASCII bytes), or
the ASCII bytes in the ASCII-only display, may be changed using standard
screen editing.

When displaying hex and ASCII from a 24-bit address, the last two bytes of
ASCII will not be displayed, due to screen width limitations.

          Peek Memory.        P adr1 [adr2..] [*]
Special memory display that allows multiple addresses to be entered, and
only prints one byte per address.  * causes a continuous print of the list
of addresses, and is really useful for finding keycodes from $D209, or
examining any locations that have changing data.  Push Break to abort the
continuous peek.

          Change Memory.      :adr by1 [by2..by8]
The change memory command ':' can be entered directly, or edited from the
display memory command.  Only 8 data bytes will be changed.  You can
substitute the character = for the adr, which will then use the current
address.  This allows you to enter successive lines of bytes without
requiring any other addresses.  Ex:

:600 1 2 3 4 5 6 7 8
:= 9 A B C D E F

          ASCII Mem Change    C adr ASCII_STRING
Stores ASCII string at adr.

          Disassemble D [M][X][R] [adr]
Disassembles memory starting at adr, or the current adr if not entered.
When disassembling 65816 code, instructions that change the register
sizes will automatically be detected, and adjust the immediate operands
in the listing accordingly.  When beginning a disassembly however, it
will not know the current state of the register sizes and will default
to 8 bits.  The M, X, and R options in the command line will force 16-bit
M, X, and both Registers to be used at the starting address.  The single
instruction that gets disassembled as part of the register display or
trace mode will always be correct, since the register sizes can be
obtained directly from the processor status register.

The disassembly code, (the instructions -- not the hex bytes), can be
modified using normal screen editing.  This gives you a single line
assembler process that is a direct link to the syntax processor in the
main assembler section.  Therefore, it uses the same format, and has all
of the same features as any one line of code that you could enter in the
assembler section.  You can use labels, < and > operators, and even
pseudo-ops!  You can enter branch instructions with an address like "*+8",
which means the current PC +8.  The only restriction is that you cannot use
a macro call.

Single line assembly can be started from scratch, (as opposed to editing
an existing disassembly), by typing, "-adr ." followed by an Assembly
mnemonic.  (The '.' is necessary).  Such as:

-600 .LDA #0

Because the period is a marker for the beginning of the instruction field,
entering a pseudo-op will require two periods.  Such as:

-600 ..HE 55 AA FF

This gives you additional methods for putting bytes into memory.  Since the
regular Change Memory command is limited to 8 bytes, you can use the above
.HE format when you want to enter more bytes than that.  Or use .BY when
you want to enter mixed strings of ASCII, HEX, and DECIMAL.  Maximum line
entry length is always limited to 80 characters though.  Other pseudo-ops
that can be useful are, .DC for blocks of constant data, and .SB for
ATASCII screen code bytes.  You can also enter the .24, .AB, .AW, .IB, and
.IW pseudo-ops to control the size of the operands that you enter, just as
you would need to do in the assembler.  None of the other pseudo-ops
produce useful results, and some can be hazardous to use.

From within the single line assembler, you may enter '*' as the first
mnemonic character to continue disassembly from that address forward.

          Display Registers   R
Displays 6502 registers in this form:

 ,A  X  Y  NV-BDIZC SP
 ;AB 5D FA 10110001 FF 7014 LDA #$00

The 65816 version of MAE displays registers in this form:

,NVMXDIZCE 0000 00 00
;00AB 005D 00FA FF 7014 LDA #$00

Status flags will be inverse when they are set, and normal when clear.
The remaining numbers on the top line are the Direct Page register, the
DBR, and the PBR.  The upper byte of the stack pointer is not displayed.
16-bit numbers for registers A, X, and Y are displayed on the next line,
however only the A register will currently show the correct 16-bit value.
Full 16-bit support for X and Y will be provided when there is an OS
upgrade readily available to handle the native mode interrupts.

Note: The Direct Page register and DBR are currently inactive, and will
always display 0.  The PBR will display the proper value, but can not be
changed by editing the register display.  Currently, it can only be set
by entering a 24-bit address into the G or I debugger commands.

          Change Registers    ; register bytes
Supports screen editing of R command.  Status flags can be modified in bit
form.  When entering values directly, a comma will skip to the next
register, and you don't need to enter all the values.  EX: ';55' will
change the A register to 55.  ';,,20' will change Y to 20.

When setting flags in the 65816 version, you can enter either normal or
inverse flag characters, or enter 0's or 1's, and can freely mix the two.

          Goto                G[S] [adr] [*brkpt] [C by] [r by] [Pf bit]
Run program at adr, or PC if not entered.  At any time during execution,
the Break key will return to the debugger and display the current
registers and PC.  Use the 'S' option to run code that ends in an RTS.
(Note:  When using the S option, the PC adr in the register display on
return is an internal address, not the address where the actual RTS
occurred.)

A breakpoint will create a return point to the debugger whenever a
particular address or condition is reached.  *brkpt will place a 00 (BRK)
at the breakpoint address.  For this reason, breakpoints can not be used
for programs in ROM.  A '?' will be printed in this case.  The breakpoint
must also be set at an opcode rather than an operand location so that it
will execute.  The rest of the parameters add conditions to the
breakpoint.

C + by Counts the number of times the breakpoint is reached.  Execution
continues until the BRK is passed the specified number of times.
Breakpoints can also test for specific conditions by specifying (r) reg
name and (by) byte it must contain in order to BRK.  Processor flags can
also be tested by 'P' + flag character + (bit) for condition.  Use the
flag characters as in the register display.

The breakpoint will be skipped over until the specific condition is
reached.  When both count and condition options are used, the count will
apply to the number of times the condition is met.  Execution speed will
be slightly slower than real time in this mode.  Actual speed will depend
on how often the program is interrupted to check conditions.

NOTE:  A peculiar bug in the 6502 chip causes breakpoints to be
intermittently skipped over.  When the BRK interrupt occurs, the program
counter+2 is pushed on the stack, but instead of jumping through the
interrupt vector, the OS will occasionally just return to the program at
PC+2.  This is usually a very rare occurrence, but can happen more often
when using conditional breakpoints on very small and quick loops, thus BRK
interrupts are occurring very rapidly.  It took many years before I was
able to really understand what was going on, and be assured that the
problem was indeed in the 6502, and not a bug in the debugger.  I
eventually found written documentation of the problem from other sources.

ADDITIONAL NOTE: This bug does not occur on the 65816 processor!

     Go command examples.
G 2000          = Run program at $2000
G 4000 *4124    = Run at $4000, and break at $4124
G *3100 A'Q     = Run at current PC and break at 3100 when A register
                  equals ASCII 'Q'
G *4200 C10 PZ1 = Run at PC and break at 4200 the 16th time the zero
                  flag is set

          Remove Breakpt      *
Brkpts remove themselves, and replace what was there when the BRK is
executed.  However, in case the program stops at other than the brkpt, *
will remove it.  This can occur when the Break key is pressed, conditional
or count values are not reached, or when the BRK is set in an operand
rather than an opcode.  Setting a new brkpt with the G command will also
remove an unused BRK.

          Exit to DOS         X [char]

When no additional characters are entered, the BRK vector at $206 will be
restored to whatever it was when MAE was started.  If you would like to keep
the BRK vector trapped by the debugger, you may enter any character after
the X.  (I could not come up with a decisive and memorable letter to use
for this purpose, so I leave it to you to choose your own.)

          Return to Assembler A

          Fill Memory         F adr1 adr2 [by1] [by2 by3...]
Fill memory with 0 if no data bytes.  Otherwise enter 1 byte, or a sequence
of any number of bytes to fill with.

          Transfer Mem        T adr1 adr2 adr3
Move memory from adr1 through adr2 to adr3.  Handles overlapping moves.

          Hunt for chars      H adr1 adr2 by1 [by2...][?]
          Hunt for String     H adr1 adr2 'ASCII string [?]
Hunt memory for ASCII string or string of hex bytes up to length of 30.
Use '?' for a wildcard to match anything.  Note that the default wild
card byte is also $3F hex, meaning that any searches with 3F in a hex
string will be treated as a wildcard as well.  See the next command for
changing the wildcard character in cases of interference.  Realize the
number entry system will let you search for things like "A9 'A", (as in
LDA #'A), but not the reverse of this.  Entering "'A A9" will put the hunt
into full ASCII form, and search for the literal string that you typed in.
The second example can actually be entered in the form "? 'A A9", using a
wildcard to avoid the initial ' identifier.  For one more example, let's
say you wanted to search for a JSR to a MAE defined label.  This can be
entered as "20 .<LABEL .>LABEL".

Searches through the OS ROM area will automatically skip $D000-$D7FF.  So
you may simply enter a search range of $C000-FFFF.

          Change wild card    ? char
Change the wild card for the Hunt command to 'char'.  This is used in case
a character in the search string needs to be '?' or HEX 3F.

          Compare mem         K adr1 adr2 adr3
Compare memory from adr1 to adr2 with memory starting at adr3.  Displays
all addresses with differences.

          DEC to HEX          # decimal number
          HEX to DEC          $ by
Displays hex values of decimal numbers and vice versa.

          Change Output       O [filespec]
Send output to screen and filespec.  O by itself returns to just screen
output.  Use "O P:" to send output to the printer.

          Re-open Editor IOCB     E
This is useful for returning to the text screen from a graphics mode, or
80-column display, or to reset the screen after changing RAMTOP.  The
other IOCB's used are:  #3 disk reads, #4 disk writes, and #6 external
output.

          Change View             V
When debugging a program that creates a new display list, the V command can
toggle between the program's screen and the debugging text screen.  The
debugger stores the display list address for the text screen, initially at
$BC20, and updates this whenever the E command is used.  The V command
checks this address against what is currently in the display list pointer,
to decide whether it needs to restore the text screen, (saving the previous
value), or return to the last saved value of your program's screen.  While
the debugger doesn't initially know where your program's screen is going to
be, it picks this information up the first time you issue the V command
with your program's screen active.

In some cases, swapping the display list pointer may not be sufficient to
display both screens in their proper format.  Such as when using different
character sets, or different GPRIOR modes.  For this reason, operation of
the V function can be extended through two user accessible vectors at
$BFF7 and $BFFA.  $BFFA will be called when switching to your program's
screen, and $BFF7 will be called when switching back to the debugger's
screen.  You can insert JMP intructions here that point to extra routines
that update whichever other hardware locations are needed.

          Query MAE symbol table  Q adr
                                     (Sorry, I was running out of letters)
Search the current symbol table for a label that matches the value entered
for adr.  If found, the label will be printed.  This is basically the
reverse procedure for symbol table lookup, and as such will only work well
when the requested value has only one label associated to it.

          Trace Instr         I [adr]
Traces program an instruction at a time.  Trace normally works on programs
in ROM, except 'G' and 'R' options as noted below.  After each step, the
debugger will wait for one of the following keypresses to control the
tracing mode:

Space - Steps one instruction at a time.
C - Continuous trace.
D - Disassemble next instructions.  Useful for previewing code that
    you are about to step through.  The program counter will remain
    at its current location.
G - Execute all instructions up to current 'D' command listing.  Use
    to quickly execute loops or other structures.  First use 'D' to
    find a spot past the structure, then 'G' will execute everything
    up to that point.  This command puts a Breakpoint at the end
    position, and therefore cannot be used if the program is in ROM.
S - Execute entire subroutine as one step.
R - Return from subroutine.  Use this command if you are already in a
    subroutine, and wish to return to the previous level.  A BRK will
    be placed at the instruction the subroutine returns to, and
    therefore cannot be used for programs in ROM.
L - Like the return from subroutine, but does an RTL return from 24-bit
    subroutine calls.
P - Peek the value of the operand of the current instruction.
    Operand calculation is crude, using simple absolute or direct page
    addressing on the operand value.  It does not attempt to calculate
    indexed or indirect operand addressing.  Thus, if you do a P on an
    instruction like "STA ($80),Y", it will return the contents of
    location $80 -- which can theoretically be useful, but the function
    is intended for use on instructions with simple absolute or direct
    page addressing modes.
Q - Perform a Q debugger command on the operand of the current
    instruction.  If the operand value is defined in the current MAE
    symbol table, the label name will be printed.  You can use this
    on JMP, JSR and branch instructions to get an idea where you're
    going, and also on any memory references that have you thinking,
    "What the heck is *that*?"
U - Execute the user function.  The carry will be clear, and $F0 will
    contain the PC for the currently displayed instruction.
V - Execute the V command to change DLIST views.
X - Ignore instruction.  Skip to the next one without executing.
ESC, RETURN, or BREAK exits trace mode.

          Change Default Drv  / 1-9
All default drive accesses change to drive number entered, including uses
in the assembler section.  The starting default drive number will be the
same as the current SpartaDOS drive.

          Binary Load         L [@adr][-adr] filename
Load DOS II binary file where it was saved, or at @adr if entered.  Prints
a '?' if the file is not DOS II format.  Loads appended files, but @adr
only works on 1st part.  -adr loads raw data with no header using a
straight CIO transfer.  Both PC and default address are set to the load
address.

          Binary Save         S [-]adr1 adr2 [@adr3] [+]file
Save DOS II binary file from adr1 to adr2.  If @adr3 is entered, it will
be used as the header allowing the file to load in at a different address
than where it was saved.  Use '-' for a CIO save without header.  If + is
entered, append to existing file.

          Directory           \ [name or spec]
                                           (Sorry, I *am* out of letters)
Displays disk directory.  Default of Dn:*.*.  A filespec of D2: = D2:*.*

          Sector Read         R adr sector# [ending sector]
          Sector Write        W adr sector# [ending sector]
Direct sector I/O to default drive.  Reads single and double density disks
automatically including single density sectors 1-3 of a DD disk.

          Evaluate Exp.       = by1(+-*/&!^\)[by2..]   (no spaces)
Prints hex and decimal values of expression evaluated left to right.
Can also be used for ASCII convert. (='A)

          User Function       U [adr1] [adr2] [adr3]
Accepts up to 3 24-bit parameters, which will be stored at $F0, $F7, and
$F3.  $F7 and $F3 will be 0 if not entered, while $F0 will have the current
address if not entered.  In addition, the carry flag will be set if no
parms.  Then jumps to the end address of the debugger-3.  ($BBFD in top of
RAM version)  User function expects an RTS return.

When the user function is called from a paused Trace or other display, the
carry will be clear, and $F0 will contain the PC or current address
respectively.

- THE DEBUG80 USER FUNCTION -

There is a file on the disk called DEBUG80.  This loads into the area for
the debugger's user function, and can be loaded either from DOS, or from
the debugger with the L command.  This function is intended to help debug
Atari programs while using the XEP80.  As mentioned earlier, the driver for
the XEP80 will not run unless the Atari's DMA turned off.  DEBUG80 provides
a toggle for the DMA control, so that the program screen can be turned on
or off as needed.

XEP80 debugging is still very limited, because you cannot issue any
commands while the Atari DMA is enabled.  Any attempts to do so, will
corrupt the XEP80 screen, and probably require turning the power to the
XEP80 off and on to recover it.  You can only toggle the DMA when the
screen display is paused, like from a memory dump or trace mode.  Still,
you may find applications where it is very helpful to view debugging
information and the screen display at the same time, and this extension
will let you do this.
