/*
** debugger.txt
**
** Copyright (c) 1997, W. Sheldon Simms III
*/

This file describes how to use the debugger built in the to program em65.
Other files document different aspects of the em65 emulator as follows:

"65c02.txt"          : how to write 65c02 programs that em65 can execute
"environment.txt"    : how 65c02 programs can use emulated devices
"implementation.txt" : how em65 is implemented

Please send suggestions, corrections to sheldon@atlcom.net

This file is current with em65 version 0.5

--------------------------------------------------------------------------

********************
*** Introduction ***
********************

Em65 provides a full 65c02 emulation, with 64kb RAM and two virtual devices,
a terminal and a disk. Upon startup, a reset interrupt is generated and
the emulated 65c02 starts executing in single step mode. The debugger is
displayed with the PC pointing at the address stored in the reset vector
at the locations $FFFC/$FFFD. At this point, the debugger can be used to
load a program into memory and execute it.

In addition, to loading and executing programs, em65's built-in debugger
allows the user to:

1) single-step through 65c02 code, stepping over subroutine calls if desired.
2) set breakpoints, and toggle them on and off
3) set watches, that display noncontiguous memory locations
4) watch the stack
5) view and edit memory anywhere in the 65c02's address space
6) view and edit the 65c02 machine registers

The following is a view of the debugger's main screen, immediately after
em65 is started with the various subwindows labeled:

registers  breakpoints    watches            disassembly
   ||          ||           ||                   ||
   \/          \/           \/                   \/
===============================================================================
  A: 00   |           |             | >>0200: A2 FF        ldx  #$FF
  X: 00   |           |             |   0202: 9A           txs
  Y: 00   |           |             |   0203: 80 0A        bra  +10     [$020F]
  S: FD   |           |             |   0205: 20 53 68     jsr  $6853
 PC: 0200 |           |             |   0208: 65 6C        adc  $6C
          |           |             |   020A: 64 6F        stz  $6F
 NV-BDIZC |           |             |   020C: 6E 20 00     ror  $0020
   +  +   |           |             |   020F: A9 05        lda  #$05
----------+           |             |   0211: 85 00        sta  $00
01FD: 00<<|           |             |   0213: A9 02        lda  #$02
01FC: 00  |           |             |   0215: 85 01        sta  $01
01FB: 00  |           |             |   0217: A0 00        ldy  #$00
01FA: 00  +-----------+-------------+----------------+-------------------------
01F9: 00  | 0200: A2 FF 9A 80 0A 20 53 68  "... . Sh | S - step     O - over
01F8: 00  | 0208: 65 6C 64 6F 6E 20 00 A9  eldo n .) | T - trace    R - run
01F7: 00  | 0210: 05 85 00 A9 02 85 01 A0  ...) ...  | B - break    W - watch
01F6: 00  | 0218: 00 B1 00 F0 07 48 8D 00  .1.p .H.. | E - edit     L - load
01F5: 00  | 0220: EC C8 80 F5 68 8D 00 EC  pH.u h..p |
01F4: 00  | 0228: 88 F0 02 80 F7 20 32 02  .p.. w 2. | D - toggle mnemonics
01F3: 00  | 0230: 80 E7 EE 36 02 60 00 00  .gn6 .`.. | Q - quit
01F2: 00  | 0238: 00 00 00 00 00 00 00 00  .... .... |
01F1: 00  | 0240: 00 00 00 00 00 00 00 00  .... .... | ESC toggles screen
01F0: 00  | 0248: 00 00 00 00 00 00 00 00  .... .... |
01EF: 00  | 0250: 00 00 00 00 00 00 00 00  .... .... |
===============================================================================
   /\                       /\                                  /\
   ||                       ||                                  ||
  stack                   memory                               menu

*******************
*** Disassembly ***
*******************

The disassembly window shows you the memory near the current PC. The PC itself
is represented by a '>>' to the left of one of the lines int the disassembly
window like this:

 >>0200: A2 FF        ldx  #$FF

This shows that the current PC is $0200 and that the instruction at that
location - the next instruction to be executed - is ldx #$FF, whose machine
language representation is the two byte sequence A2 FF.

The disassembly area does what it says, it disassembles everything it can -
even if the contents of memory are really supposed to be data. Look at the
lines from $0205 to $020C:

   0203: 80 0A        bra  +10     [$020F]
   0205: 20 53 68     jsr  $6853
   0208: 65 6C        adc  $6C
   020A: 64 6F        stz  $6F
   020C: 6E 20 00     ror  $0020
   020F: A9 05        lda  #$05

They are disassembled as instructions even though they are not apparently
executed since the instruction at $0203 is an unconditional branch around
them. Looking at the memory window (to jump ahead for a moment) we see:

                      ->
 0200: A2 FF 9A 80 0A 20 53 68  "... . Sh
 0208: 65 6C 64 6F 6E 20 00 A9  eldo n .)
                         <-

Aha, those bytes are actually letters spelling my name, and not really
supposed to be instructions at all! But the disassembly window doesn't know
that, so it disassembles them anyway.

Sometimes the disassembler can tell when memory contents are not code.
For example this can happen if the contents of memory are not valid 65c02
opcodes. In this case, the disassembler displays the bytes as data, up
to four bytes on a line, looking like this:

   02F8: 0F 1F 2F 3F  [../?]

No byte with a low nibble of F is a valid 65c02 opcode, therefore these
four bytes are displayed as data. The four bytes are followed by their
ASCII equivalents, with non-printing characters displayed as '.'. Of
course, this makes actual '.' characters (ASCII $2E) hard to spot, but
that's just something you have to live with.

Some parts of the 65c02 address space are not mapped to RAM. The space
from $EC00 to $ECFF is I/O space, and cannot be read and written to
like RAM. Therefore, it is not displayed in the disassmbly window. If
the PC gets near I/O space, lines will be displayed in the disassembly
window looking like this:

   EBFx:                        <- normal disassembly here
   EC00:   *** I/O space ***
   ED00:                        <- normal disassembly here

In the menu area there are three selections that affect the disassembly
area:

 S - step     O - over
 T - trace

 D - toggle mnemonics

Step causes the 65c02 to execute the next instruction, the one preceded
by '>>'. The '>>' will advance to the next instruction to be executed,
scrolling the disassembly area if necessary.

Over is the same as step except that subroutines are stepped over. If
the next instruction is a 'jsr', Over will cause the 65c02 to execute
continuously until it reaches an 'rts' instruction without updating
the debugger screen at all. For example, if the disassembly window
contains:

 >>0428: 20 4C 30     jsr  $304C
   042A: 85 2F        sta  $2F

After selecting Over, the disassembly window will contain:

   0428: 20 4C 30     jsr  $304C
 >>042A: 85 2F        sta  $2F

All of the code starting at $304C, up to and including an 'rts'
instruction was executed, but it was done silently - the debugger was
not updated.

Trace works exactly like selecting Step over and over again. The
debugger is updated after every instruction, but the debugger does
not stop to allow you to select another command, it immediately
executes the next instruction. There are two ways to stop trace -
one is to set a breakpoint before selecting Trace, see the Breakpoints
section for more information.

The other way is to press Control-C. Control-C will stop the emulated
65c02, redraw the debugger screen, and allow you to enter another command

Toggle mnemonics, switches the assembly language mnemonics used to display
the disassembled code between the standard set (which is used by default)
and a second set intended to make the orthogonality of the 65c02
instruction set more clear. (to the extent that it is orthogonal, which
is more than the standard mnemonic set makes it seem, but less than
it perhaps should be)

As an example, here are some lines from the built in program shown in
both mnemonic sets:

Standard                          Orthogonal

0219:  lda  ($00),Y               0219:  mov  ($00)+Y,A
021B:  beq  +7      [$0224]       021B:  beq  +7      [$0224]
021D:  pha                        021D:  psh  A
021E:  sta  $EC00                 021E:  mov  A,$EC00
0221:  iny                        0221:  inc  Y
0222:  bra  -11     [$0219]       0222:  bra  -11     [$0219]
0224:  pla                        0224:  pul  A
0225:  sta  $EC00                 0225:  mov  A,$EC00
0228:  dey                        0228:  dec  Y
0229:  beq  +2      [$022D]       0229:  beq  +2      [$022D]
022B:  bra  -9      [$0224]       022B:  bra  -9      [$0224]
022D:  jsr  $0232                 022D:  jsr  $0232


**************
*** Memory ***
**************

The memory window allows you to display and edit any part of the 65c02's
address space. When you load a program into the 65c02's memory, the memory
window is set to display memory starting at the load address. You can change
what part of memory is displayed by selecting

 E - edit

from the main menu. Doing so, will change the menu so that it looks like
this:

 R - edit registers
 M - edit memory

 Q - don't edit anything

Selecting 'R' will allow you to edit the 65c02 machine registers - see
the Registers section for more information. Selecting 'M' will change the
menu again to this:

 hjkl - left,down,up,right
 C-f  - page down
 C-b  - page up

 ESC  - quit

The cursor will also move to the first memory location displayed in the
memory window. You can type two hexadecimal digits to change the contents
of the currently selected memory location.

The "vi-keys" hjkl allow you to change the current memory location to
the one to the left, right, above, or below the current, scrolling the
memory window if necessary.

Control-F will scroll the memory window up by $50 (decimal 80) bytes while
Control-B will scroll the memory window down by $50 bytes.

To stop editing memory, hit ESC.

If you edit a part or memory shown in any other part of the debugger screen -
you edit some code shown in the disassembly window, or you edit the stack,
the changes will immediately appear in all affected windows, even re-
disassembling the code in the disassembly window if necessary.

*************
*** Stack ***
*************

The stack window shows the part of the stack ($0100 to $01FF) near the
current stack pointer. The current stack point is indicated by a line
which is followed by '<<' like this:

----------+
01FD: 00<<|
01FC: 00  |
   ...    |
----------+

It is thus very similar to the indication of the PC in the disassembly
window. If you wish to edit the stack, you must do so by using the memory
window. The changes will be displayed in the stack window. The stack
window itself is just a display that lets you see how subroutine calls are
working.

*****************
*** Registers ***
*****************

The registers window displays the 65c02 machine registers and allows you
to edit them as well. It looks like this:

  A: 00   | <- 65c02 accumulator
  X: 00   | <-
  Y: 00   | <- 65c02 index registers
  S: FD   | <- 65c02 stack pointer
 PC: 0200 | <- 65c02 program counter
          |
 NV-BDIZC | <- 65c02 status flags (often called register 'P')
   +  +   |
----------+

You may be wondering why PC and S are included here. After all, their value
is also displayed in the disassembly window and stack window respectively.
They are in the register window so that they can be edited.

When stepping or tracing 65c02 instructions, the contents displayed for
the various registers are updated to reflect any changes after each
instruction is executed. This can be very useful to let you see if a 65c02
program is correct. (It can also show you that the 65c02 emulation is
wrong, but let's assume that I would NEVER allow a bug like that to creep
into >MY< code!)

To edit the registers, you select

 E - edit

from the main menu and then select

 R - edit registers

from the menu that follows. The menu will change to include the following:

 RET - next register
 SPC - toggle flags
 ESC - quit

and the cursor will then move to the diplayed value of the 65c02 accumulator.
You can enter two hexadecimal digits to change the contents of A, or hit
return or enter to move the cursor to the next register.

When you get down to the status flags, return moves from one flag to the
next and you can hit the space bar to toggle a flag. Hit ESC when you are
finished editing registers.

***************
*** Watches ***
***************

The watch window is empty when em65 is first started, because there are
no watches defined. A watch is a way of keeping track of the contents of a
particular memory location, even if the location is not being displayed
in the stack, memory, or disassembly windows. To add or delete a watch
select

 W - watch

from the main menu. The menu will change to become:

 A - add watch
 K - kill watch
 D - done

If you select A - add watch, you will be prompted:

 Address:

Type the address of the location you want to watch as 4 hex digits and
then hit return (or Enter). The watch will be displayed in the watch
window. For example if you type:

 Address: 0236<ret>

The watch window will display:

  1 0236: 00

This line shows that watch #1 is location $0236, and that the contents of
that location is the byte $00.

If you want to delete this watch, you can type K - kill watch from the watch
menu. You will be prompted

 Which:

Type the number of the watch you wish to delete and then hit return (or
Enter) and the watch will disappear from the watch window. Type D - done
to quit adding and deleting watches and leave the watch window.

*******************
*** Breakpoints ***
*******************

Setting breakpoints is one of the fundamental operations in any debugger.
When em65 is first started the breakpoints window is empty because no
breakpoints have been defined yet. Breakpoints are defined very much like
watches are. To define a breakpoint, select

 B - break

from the main menu. The menu will change to:

 A - add breakpoint
 K - kill breakpoint
 T - toggle breakpoint
 D - done

If you select A - add breakpoint, you will be prompted:

Address:

Enter an address just as you do for watches. For example, you may enter

Address: 0204<ret>

And the line:

  1 + 020F

will appear in the breakpoint window. This line tells you that breakpoint
#1 is at address $020F and that it is currently enabled. If you select
K - kill breakpoint, you can then select a breakpoint to delete, in
exactly the same way you delete a watch. If you select T - toggle breakpoint,
you select a breakpoint to toggle and it is toggled. For example, if you
select T - toggle breakpoint and then type

 Which: 1<ret>

The breakpoint shown above will change to look like this:

  1 - 020F

The plus has changed to a minus. This means that the breakpoint is disabled,
although it still exists. To reenable the breakpoint just T - toggle it
again.

Well after all that explanation, what is a breakpoint for? A breakpoint is
an address at which the 65c02 execution will cease and control will be
transferred to the debugger so that you can enter another command.

When a breakpoint is disabled, it does not cause execution to stop. So if
you want to break at a certain address some of the time, you can set a
breakpoint there and then disable it before you run the 65c02 program if
you don't wish for the program to stop at that address that time.

Breakpoints in the em65 debugger are all unconditional breakpoints. That is,
if they are enabled, they always cause execution to stop at their address.
Many debuggers offer conditional breakpoints, where execution will stop only
if some condition is true - only if the contents of the accumulator equal
$4C, for example. This capability is not offered currently, but it will
most likely appear in a future version.

It was mentioned in the disassembly section that breakpoints are one way to
stop a trace. This should be obvious by now. Breakpoints can be similarly
used to stop a run, which is continous execution without updating of the
debugger. This is discussed further in the next section.

******************
*** Load & Run ***
******************

Of course, probably the most important ability of the debugger hasn't been
discussed yet - the ability to load and run arbitrary 65c02 programs. This
frees you of the tyranny of the built in program and it's homage to yours
truly. With the load and run capabilities, you can write a program to
print *your* name over and over!

If you wish to load a program, you must first have a program to load. While
you could make a program by hex editing a file, that would be a pain. The
preferred way to to use a text editor to write the program in 65c02 assembly
language and then use an assembler to generate a binary image. Any assembler
can be used as long as it is capable of generating a binary image, also
known as a ROM image, since making a ROM is usually why you would create a
binary image. Although assemblers for more modern processers often gripe
and complain, telling you that making binary images is Bad (note the capital
'B'), 65c02 assemblers rarely complain, because most 65c02 code is written
as absolute code. In any case, a good free assembler to use is called XA
and it is written by Andre Fachat. See the file "65c02.txt" for more
information about writing your own programs.

Assuming you have a binary image to load, select

 L - load

from the main menu. You will be prompted

File (ESC to abort):

type the filename of the binary image, as figured from the current
directory. The debugger isn't too smart about directories right now, but
you can type something like

../../myprogs/em65/emacs.o65

and it will be happy (assuming the file actually exists). You will then be
prompted:

Address:

type the memory address at which you want the program to be loaded as four
hexadecimal digits followed by return (or Enter). The address you type
should be the same address that the program was assembled for. This
address is usually specified in assemblers by a line at the beginning of
the program like this:

            org  $D000

or

            *=   $2000

The binary image will then be loaded into the 65c02's memory at the
specified location and the PC will be changed to the address you typed.
The memory window and disassembly windows will change so that their
display begins at the specified address.

At this point, you can Step, Over, or Trace the program as described in
earlier sections. However, if you wish to dispense with the debugger and
let your program reign as the undisputed master of em65, you can select

 R - run

from the main menu. When you select run, the debugger screen disappears and
is replaced with the virtual terminal screen. Any output that your program
sends to the virtual terminal will be displayed instantly on the screen and
you can type characters on the keyboard for your program to receive.

But what if your program has a bug? (after all it's your program, not mine)
Suppose it enters an infinte loop and locks up? Just hit Control-C and
the debugger will be restored. Now you can step through the code and see
why your program messed up. Of course, this means that your programs can't
read Control-C from the keyboard. Once again, this is just one of those
things you have to live with, at least for now.

Also, if your program reaches a breakpoint while running, it will stop and
return to the debugger. It might be a good idea to set a breakpoint on
the part of your interrupt handler that detects the execution of BRK
instructions (you do have one right?), as that should cause the debugger to
be invoked whenever the 65c02 tries to execute garbage.

Lastly, you may want to know how you can see the output your program sends
to the virtual terminal when it isn't running. For example, if you are
stepping through your program and come to a place where it prints, you might
want to see if the printing is happening correctly. In the debugger you
can hit ESC to switch to the virtual terminal screen. Unless your program
is running, it still cannot receive input from the keyboard - all input
goes to the debugger even if the debugger screen is hidden, but you can
see the output. So it is possible to hit ESC to show the virtual terminal
screen and then hold down the 'S' key to see your program executing very
slowly, writing characters   o n e   a t   a   t i m e.

===============================================================================

