Hexpert and Hexpert's manual are (c) copyright Advanced Software Systems, 1990.
Commodore 64 is a registered trademark of Commodore Electronics Ltd.
Commodore 128 is a registered trademark of Commodore Electronics Ltd.
geoDebugger is a registered trademark of Berkeley Softworks
TurboDebugger is a registered trademark of Borland International
Manual written by Eric Trepanier (release 1.0)
Hexpert designed and written by Eric Trepanier
A Few Words from the Author
As an active Commodore 128 programmer, I have every intentions of improving Hexpert and make it more and more versatile and powerful. This software is released as Public Domain, which means I am granting you the privilege of using it at your discretion. I am not expecting any financial compensation out of this program. You can freely distribute it, and what the hell, you can even sell it if you can find someone silly enough to pay anything for it. This is not to say that Hexpert is not a good program. In fact, I am not sure they are other debuggers available for the C128, besides geoDebugger. The only thing I expect from the programmers who will actually use it is some feedback, either good or bad. I want this program to be the "BEST" debugger for the C128.
This is only an initial release, but future versions will include much more advanced features. However, if I don't get any feedbacks, I'll have to conclude that it's not worth spending time on it. Any suggestions, criticism, or simply a wish-me-luck card will be appreciated...
Eric Trepanier
NOTE: If you do distribute this program, please distribute it in its entirety, with all the documentation files. Needless to say that a modified copy of Hexpert should not be distributed.
Credits
This program might never have seen the light of day without the presence of a good friend of mine named Pedro, who happens to be an excellent machine language programmer himself. Without his help, I would never have mastered machine language so easily. I would also like to thank a couple of my friends for their encouragements and support. These friends are Sylvain Tremblay, Philippe Blais and Marc Veilleux.
Disclaimer
Let's get this over with... This program and accompanying documentation come with no warranty, either express or implied, with respect to accuracy or suitability for any particular application. The author assumes no responsability whatsoever for any damage, direct or incidental, resulting from their use. Good, now on to the more interesting stuff!
Table of Contents
Chapter 1
Introduction to Hexpert
What is Hexpert? 6
Manual Organisation 6
The Origin of Hexpert 7
Chapter 2
Hexpert Usage
What is a Debugger? 8
Hexpert Features 8
Dual Displays 9
Breakpoints 9
Running Hexpert 9
Sample Hexpert Session 10
Chapter 3
Hexpert Reference
Command Syntax 13
The Concept of Memory Banking on the Commodore 128 14
Hexpert Command Summary 15
General Commands 16
Display Commands 18
Execution Commands 21
Breakpoint Commands 25
How Breakpoints work: The Ins and Outs of Breakpoints 25
Appendices
Appendix A
Information Messages 27
Error Messages 27
Appendix B
Debugger Dependency 29
Off Limits Memory 29
Miscellaneous 29
Appendix C
Commodore 128 and the 8502 Machine Language 30
Chapter 1: Introduction to Hexpert
What is Hexpert?
Hexpert is a simple program, designed to be used in conjunction with the C128's built-in machine language monitor. This is part of the reason why even though it is relatively small (2K), it still has a lot of features to offer. Hexpert makes as much use as possible of the monitor's own routines (e.g. symbolic disassembly, numeric conversions, etc.). The main purpose of Hexpert is to allow you to monitor your programs as they are executed. This is what a debugger is for. Several commands are available to allow a close watch of the program's state at any time during its execution.
Manual Organisation
This manual is organised in the following manner:
Chapter 1 is the introduction chapter. This chapter needs only to be read if you wish to know more about the development of Hexpert. It is not essential for making good use of Hexpert.
Chapter 2 presents a brief discussion on the concept of "program debugging". It presents some of the major features of Hexpert. At the end of the chapter, there is a complete "hands-on" sample session to illustrate these functions. Although not essential, this chapter will make a good introduction on how to actually use Hexpert. It would be a good idea to read it through before using the debugger.
Chapter 3 is the reference chapter. This is the most important chapter, it presents all the debugger's commands as well as examples on how to use each of them.
Appendix A explains all the debugger's information and error messages, appendix B contains all the technical information concerning Hexpert and appendix C presents a small C128 machine language bibliography.
The Origin of Hexpert
Recently, I started working on a window package, with commands for opening, closing, moving and resizing windows. I quickly realized I could hardly debug the subroutines without the help of something more evolved than the C128's monitor. This is how I got the idea for Hexpert. At first, I didn' t think of releasing it in the Public Domain. I was doing this program for my personnal needs, end of the line. A friend of mine who saw an early version of Hexpert running was impressed. He suggested that I add some features and release it as a shareware program. So I did add a few options here and there, and made it what it is now. However, I felt kind of shamed to release it as shareware. There are so many good PD programs out there. I just felt I owed it to them to release my own program as Public Domain. Besides, it didn't take me more than a few weeks to finish the program. Some shareware programs take years to create (e.g. DesTerm 128 v2.00 from Matthew E. Desmond) and yet their authors only charge a ridiculously small fee for their use.
It's up to you, the users, to turn Hexpert into a real bug killer. Just send in your comments on Hexpert. Let me know if you discover any "undocumented features". Every suggestions will be considered. If I see that it is used, I might rework it over and turn into a serious TurboDebugger competitor.
Chapter 2: Hexpert Usage
This chapter introduces the major features of Hexpert as well as overviewing how to run and use the debugger. It begins by describing the concept of debugging and finishes with a short tutorial covering the basic features of Hexpert. This chapter does not cover aspects of the debugger in exhaustive detail. Refer to the following chapter for more complete coverage.
What Is A Debugger?
Unless you are an exceptional programmer, your programs will seldom work right away. Most of the time, they will be "bugged". Bugs are the little mistakes and errors that you haven't noticed while coding your program. It might be an incorrect jump or a bad branch, or it could be something much less obvious. In such cases, it's very hard to know exactly what is going wrong. Maybe your algorithm has a logical error, but unless you can trace your program step by step and monitor all important variables, you will have a very hard time fixing the problem. This is where a debugger comes in handy. With it, you can set up breakpoints in your program and then execute it. When your program reaches the breakpoints, it will stop and you can monitor all the 8502 registers and important variables. You can also watch your program's execution instruction by instruction. The debugger is perhaps the programmer's most important tool.
Hexpert Features
Hexpert is a software debugger that is accessed via the C128's monitor. A lot of work has been put to make Hexpert as small as possible, yet big enough to hold a complete arsenal of useful debugging commands. The result is a surprisingly versatile 2K debugger with all the important features one could expect from an expensive commercial debugger package.
Hexpert offers a plethora of commands to help you monitor your program and memory, giving you full access to both C128's RAM bank, I/O registers, Kernal ROM and all 8502 registers. You can disassemble, modify and run your program interactively, setting break points, displaying and changing register values.
Dual Displays
Hexpert makes use of both the C128's forty and eighty column display. This allows you to debug on the forty column screen a program which accesses the eighty column screen, so the program's output will not be disturbed by Hexpert's output. This feature works best if you have access to two monitors (CRTs). Hexpert could be run on one monitor while the program's output appears on the other monitor. Even geoDebugger doesn't allow this possibility! The screens may be swapped at anytime during the program's execution.
Breakpoints
Hexpert supports a user-breakpoint facility in a limited fashion. Breakpoints may be set anywhere in RAM memory. Once a breakpoint is encountered during program execution, the program stops and Hexpert is given control. Due to memory conflicts, this version of Hexpert doesn't allow the use of a single break point more than once. This means that once a breakpoint has been reached, it is removed from the program. Hexpert allows ten simultaneous break points.
Running Hexpert
There are many ways to activate Hexpert. If your assembler/linker doesn't alter memory in the range $1300-$1BFF, you can have Hexpert bloaded before calling the assembler. Merlin 128 works fine this way. If you want to use Hexpert with Merlin 128, just add the <BLOAD "HEXPERT"> line in the "MERLIN" basic boot program from the Merlin boot disk. When you use Merlin's "Exit to BASIC" option, you only need to type SYS 4864 to activate Hexpert.
You can also boot hexpert directly (i.e. BOOT "HEXPERT"), or have Hexpert auto-booted using the C128 autoboot maker on the 1571 demo disk.
Whichever way you choose, you should see the "HEXPERT Vx.x" copyright message appear when the SYS 4864 is executed.
Hexpert should work fine with other monitor enhancements provided that the other programs do not alter memory range $1300-$1BFF and that Hexpert is booted first.
Once you've seen the "HEXPERT Vx.x" message, the debugger can be accessed
via the "E" command in the C128's monitor.
Sample Hexpert Session
This section is a hands-on tutorial. It is designed to familiarize you with the debugger environment. You will need a disk with the HEXPERT program file on it.
Begin by resetting your C128. When the "READY." prompt appears, type the following:
BOOT "HEXPERT" + [RETURN]
Eventually, a message like this should appear:
HEXPERT V1.1 (C) 1990
BY ADVANCED SOFTWARE SYSTEMS
READY.
Again, at the "READY." prompt, type MONITOR + [RETURN], or hit the F8 key. You will enter the C128's monitor which should look like this
MONITOR
PC SR AC XR YR SP
;FB000 00 00 00 00 F8
When the cursor starts flashing, type E + [RETURN]. This will call Hexpert which will respond with the following:
DEBUGGER
PC AC XR YR SP NV-BDIZC MEMMAP
;1B000 00 00 00 F8 00000000 01001110
. 1B000 xx xx xx AAA OOOO
DEBUG>
This is a representation of the 8502 registers and of the next instruction to be executed in mnemonic format at the current value of the program counter. The xx xx xx refers to the binary format of the instruction, opcode first, operand second in a low/high byte fashion. The AAA is the mnemonic for the opcode and OOOO is the operand.
The cursor should be flashing after the "DEBUG> " prompt. This means that Hexpert is awaiting a debugger command. Unfortunately, we do not have a program to run yet... This is not too bad though, we will use the monitor to assemble a small program which we may then execute step by step. You should now exit using the Q command. It is not necessary to hit the [RETURN] to execute a command while you are under Hexpert's "DEBUG> " prompt, Hexpert knows when a command is complete. Now that we are back in the monitor, we will assemble a small program at $2000. You should refer to the C128 manual for help with the C128 monitor. Enter the following lines:
A 02000 A9 00 LDA #$30
A 02002 A2 00 LDX #$00
A 02004 9D 20 20 STA $2020,X
A 02007 38 SEC
A 02008 69 00 ADC #$00
A 0200A E8 INX
A 0200B E0 04 CPX #$04
A 0200D D0 F5 BNE $2004
A 0200F 00 BRK
This program performs a small loop which stores the ASCII codes of 0,1,2,3 consecutively at $2020. Before we enter Hexpert, let's take a look at what's in $2020. Type M2020 + [RETURN]. You should get a following display:
>02020 xx xx xx xx xx ...
Remember the first five bytes starting at $2020. Write them down if you have too, we will execute the program and verify that the values have effectively been changed. Now let's enter Hexpert again, type E + [RETURN] again.
Once you get the "DEBUG> " prompt, type 02000; S. Once you get used to Hexpert you will notice that many commands may be abbreviated. The previous command could've been abbreviated to "02S" with the same result. This sets the program counter at $02000 which is where our program resides. You can hit the ESCAPE key at any time to cancel a command. Now that we have something like this:
. 02000 A9 00 LDA #$30
DEBUG>
We will start executing the program step by step. Hit the S key. The register will appear again. This time, AC will hold the value 30. The next instruction at $2002 is displayed. Hit S again to execute it. The registers will appear again unchanged, except for the Z bit in the status register which should have been set to one. This is ok, since we loaded the value zero in the x register. The next instruction stores the contents of the accumulator at $2020 + x, where x is the value of the x register. Then the carry is set. The corresponding bit of the status register should be set to one accordingly. The ADC #$00 will add the carry to the contents of the accumulator. Result: AC = $31 and bit C is cleared. Then the X register is incremented and compared with the value 4. If it is not equal, the program branches back to $2004 and the loop is executed until the x register holds a value of 4 at which time a BRK instruction is encountered which indicates the end of the program.
This is a very simple program which doesn't do much, but it shows the main components encountered in a program: loops, tests and jumps. You might think that it is annoying to always have the registers displayed after every instruction (I do!). You can hit the D key to toggle the register display option on/off. When it is off, you will have to hit the R key to see the registers.
Now we want to confirm that the program did store the values at $2020. We'll use the SHOW BYTE command "\", to do this. Type 02020; \. You will get:
DEBUG> 02020; \02020 = 30
With the cursor positioned to the right of the 30 value. Indeed, this is the value which we had stored at $2020. Hit the LINE FEED key to see the next byte, which will show a value of 31, this is also good. The next two bytes will have also changed to 32 and 33. The fifth byte however has not been modified, so its value should be intact. If you think Hexpert is playing a magic trick on you, you can use the monitor's M command to make sure.
And Now On To More Powerful Manipulations
Now that you have completed the sample session with Hexpert, you should be beginning to feel more comfortable with the debugging environment. You will find a complete discussion of Hexpert's command set in the following chapter.
Chapter 3: Hexpert Reference
This chapter contains a complete reference of Hexpert's command set. It covers every aspect of using the debugger such as jumps, step by step, breakpoint and view options, including a detailed description of each command. Although this is primarily a reference chapter, it would be a good idea to read it through completely at least once. For a general overview and information and information on using the debugger, refer to the previous chapter.
Command Syntax
Hexpert uses an interactive parser which knows what to expect from a command. This is why it is seldom required to hit RETURN to confirm, or to add separator characters like spaces or the likes. In addition, every command which requires (or accepts) an address can be abbreviated if the address has terminating zeros. For example, if you want to start execution at $3000 in bank 1, the entire command should look like this:
DEBUG> 13000; G
However, the space and the ';' character are added automatically by Hexpert's parser if you omit them. The zeros can be omitted too, thus you could simply type 13G and obtain the same result. At any time while entering a command, use the ESCAPE key to cancel the command. It is not possible to use the delete key however...
NOTE: All commands are entered UNSHIFTED.
The correct syntax for an address is the following: Bhhhh. All addresses require four hexadecimal digits h, though the zeros will be appended by Hexpert if necessary. The B stands for BANK number. The current version of Hexpert offers a limited BANK support. Only RAM bank 0 or 1 may be accessed. Memory in the range $D000-$DFFF is always mapped as I/O registers. Memory beneath it is currently inaccessible, this will probably change in an upcoming version. Memory in the range $C000-$FFFF can be toggled as either RAM (0/1) or ROM Kernal. Keep in mind that the ROM kernal can not be single-stepped.
Some commands will require an additional parameter following the command code. This parameter should be a decimal number (0-9).
The Concept of Memory Banking on the C128
The C128 is an eight bit machine. This means that it's processor (8502) can handle information that is 8 bits wide. The C128 address bus handles 16 bit addresses, so the C128 can only address up to 64K of memory. You are probably wondering how the C128 can have 128K of RAM memory, if it can only handle up to 64K, right? Well, it just so happens that a special device on C128 mother board is in charge of handling all the memory switching of the C128. This device is called the Memory Management Unit (MMU).
The RAM memory of the C128 consists of two 64K RAM banks. Only one of these banks can be accessed at a time. Additionnaly, the C128 has a fair amount of ROM memory (BASIC 7.0, Machine Language Monitor, Kernal) as well as a 4K block of input/output registers. All of these need to be accessed by the C128 too. The MMU is in charge of establishing different memory configurations that will enable the 8502 to access all of that RAM/ROM memory. You might be familliar with BASIC's BANK command which allows you to choose one of fifteen pre-set memory configurations. These configurations are only a subset of all the possible combinations that might be selected. The machine language programmer has full control over the MMU through a dozen of I/O registers. We are not going to expand any more on the MMU, please refer to the C128 Programmer's Reference Guide for more information on the use of the MMU's input/output registers.
Hexpert acknowledges some of the different configurations that might be selected by a program, notably it will permit a program to freely access RAM memory from bank 0 or 1. It allows the Kernal ROM to be accessed as well as the input/output registers at $D000. It does not allow access to the BASIC & Monitor ROM, nor does it allow you to access the 32K ROM sockets.
The programmer can select where in memory the program is located via the first digit of every addresses specified at the "DEBUG>" prompt. This digit should be a 0 or 1 and corresponds to one of the two 64K RAM memory blocks. The "MEMMAP" register display is an image of the program's actual MMU configuration.
Hexpert Command Summary
General Commands
Q Exits Hexpert and returns to the C128's monitor
D Register display toggle for step by step execution
K Kernal toggle (memory range $C000-$FFFF)
^ Hexpert screen toggle (40/80 columns)
General Display Commands
R Display processor registers
A View/Modify contents of accumulator
X View/Modify contents of x register
Y View/Modify contents of y register
\ View/Modify contents of a byte
/ View/Modify contents of a word
Execution Commands
G Start full speed execution of program
J Execute subroutine at PC (must be on a jsr instruction)
S Single step through current level and subroutines, also used to set new program counter
T Top step through subroutines using inline parameters
Breakpoint Commands
B Set/Remove breakpoint
General Commands:
Command: Q
Purpose: leave the debugger and return to the monitor.
Usage: Q
Note: takes no parameters.
Q leaves the debugger and returns to the C128's monitor. The programs space remains intact as do the 8502 registers, so it is possible to toggle between the monitor and the debugger during the execution of a program to use the monitor's extended memory view capabilities.
Command: D
Purpose: toggle the display of 8502 registers during step by step execution.
Usage: D
Note: takes no parameters.
D toggles the automatic display of the 8502 registers during step by step execution. The automatic display might be practical during critical program sections, but most of the time, it is mostly annoying. This option uses the BEEPER flag in zero page $F9 to determine whether it's on or off. This has an effect on the output of the bell (CHR$(7)). When the automatic display is turned off, the bell can't be heard.
Command: K
Purpose: Toggle contents of memory in range $C000-$FFFF between RAM and ROM.
Usage: K
Note: takes no parameters.
K toggles what is found by Hexpert in memory range $C000-$FFFF for program execution. This means that it is possible to run programs which use the Kernal in RAM BANK 0 or 1. This is reflected by bit 4 and 5 in the MEMMAP display. When both bit are set to zero, ROM will be accessed. When both bit are set to one, RAM will be accessed. The RAM BANK will depend on bit 6 of the MEMMAP. A clear (zero) bit 6 means RAM BANK 0 is accessed, while a set (one) bit 6 means RAM BANK 1 is accessed.
NOTE: It is not possible to use the b,s,t,j,\,/ commands in ROM. Such commands are not forbidden by Hexpert, but they will however have unpredictable results and may very well crash your system. See the S command for information on how to single-step through the Kernal's routines.
Command: ^
Purpose: Toggles Hexpert's active screen between forty and eighty columns.
Usage: ^
Note: takes no parameters.
^ toggles Hexpert's active screen (the one in which Hexpert's "DEBUG> " prompt appears. If you want to debug an 80 column-specific routine, then Hexpert's active screen should be in forty columns. The same holds true for the opposite situation. You can make the best use of this feature by connecting two monitors to your C128. One monitor should be connected to the RGB port, while the other is connected to the Composite output.
NOTE: While you are debugging applications that use the VDC, select the 40 column's screen as the active Hexpert screen. This way, Hexpert's output will not affect the READY bit of the VDC register ($D600).
Display Commands:
Command: R
Purpose: Display processor registers.
Usage: R
Note: Takes no parameters.
The R command displays all the processor registers, including the MMU pseudo-register. The output has the following format:
PC AC XR YR SP NV-BDIZC MEMMAP
;1B000 00 00 00 F8 00000000 01001110
The PC, AC, XR, YR and SP indicators refer to the program counter, accumulator, x register, y register and stack pointer. NV-BDIZC are the seven bits of the status register. The "-" bit is not used. Do not pay attention to it. The most complicated of the registers displayed is the MEMMAP, which refers to the C128 MMUCR register. Refer to the C128 PROGRAMMER'S REFERENCE GUIDE for information on the MMU. This indicator shows the actual program's MMU configuration. Below the registers, the next instruction to be executed at the current PC is also displayed.
Command: A
Purpose: View/Modify current value of accumulator.
Usage: A
Note: Takes no parameters.
The A command (as well as the X and Y commands) is used to view and modify the current value of this 8502 register. When used, it will look like this:
DEBUG> AC = xx
The cursor will appear after the xx value (hexadecimal). This value may then be changed or cleared using the DEL key and hexadecimal keys (0-9,A-Z). To confirm the new value, simply hit [RETURN]. You can abort modifying the current value using the ESCAPE key. The value needs not to have two hexadecimal digits. If no digits are entered, the value zero will be given.
Command: X
Purpose: View/Modify current value of x register.
Usage: X
Note: Takes no parameters.
This command is similar in use to the A command. Refer to the A command description for more information.
Command: Y
Purpose: View/Modify current value of Y register.
Usage: Y
Note: Takes no parameters.
This command is similar in use to the A command. Refer to the A command description for more information.
Command: \
Purpose: View/Modify byte value at specified address (PC if none provided).
Usage: [addrexp]\
Note: addrexp is the address of the byte to view. If no address is specified, the current address pointed by the PC will be used. This command is similar in use to the A command.
The \ command is the general view and modify data command. When you open a memory location with \, you are placed in an interactive mode. You can then either change the current value and confirm with the return key, abort changing the value using the escape key, or leave this value unchanged and view the next byte using the LINE FEED key. You can cycle through the entire memory, viewing one byte at a time using the LINE FEED key.
It is also possible to switch to the VIEW WORD mode which is described next by hitting the / key.
Example:
04000; \ view byte at address $4000 in BANK 0
\ view byte at current PC
Command: /
Purpose: View/Modify word value at specified address (PC if none provided).
Usage: [addrexp]/
Note: addrexp is the address of the word to view. If no address is specified, the current address pointed by the PC will be used. This command is similar in use to the A command.
The / command is much like the previous command, VIEW BYTE. However, this one allows you to view a whole word in its correct representation. Thus if bytes C5 and 60 are stored consecutively at $3000, the 03000; / command will give the following display:
DEBUG> 03000; /03000 = 60C5
Notice how the two bytes have been inverted. This is consistent with the 8502's LO/HI byte representation. Other than that, this command behaves much like the VIEW BYTE command, although it has an added option: @. When the @ key is typed, you get the value of the word at the address that you were previously viewing as a word. This sounds complicated but it really isn't. Let's say you would press the @ key while viewing the contents of $3000, then you would get the word value at address $60C5 (provided that $3000 holds the $60C5 value). This is useful when you are viewing complex list structures with lots of pointers to sub-lists and so on.
It is also possible to switch to the VIEW BYTE previously described by hitting the \ key.
Example:
04000; / view word at address $4000 in BANK 0
/ view word at current PC
Execution Commands:
Command: G
Purpose: Begin full-speed execution of program.
Usage: [addrexp]G
Note: addrexp is the address to begin execution. If no address is specified, the current address pointed by the PC will be used.
The G command starts full-speed execution of the program. Control will not return to Hexpert unless a breakpoint or a brk instruction is encountered.
Example:
02000; G begin execution at address $2000 in BANK 0
G begin execution at current PC
Command: J
Purpose: Execute a subroutine at current PC.
Usage: J
Note: Takes no parameters.
The J command is only a T0 command in disguise. It will only have effect if the instruction at the current PC is a jsr instruction. If so, Hexpert will set a brk instruction after the jsr and will perform a JMPFAR at PC. This may sound a bit complicated. What it means is that the subroutine at the current PC will be executed and control will return to Hexpert after the routine is executed.
NOTE: It is important that the return address on stack is not modified by the subroutine or else, control will not return to Hexpert, which could have unpredictable results.
Example:
. 02000 20 D2 FF JSR $FFD2
DEBUG> J execute routine at $FFD2
...
. 02003 xx xx xx AAA OOOO
DEBUG> control returns to Hexpert after RTS
Command: S
Purpose: Single step through instructions and in and out of subroutines, also allows to set a new PC value when used with an address.
Usage: [addrexp]S
Note: addrexp is used to set a new program counter value. If no address is specified, the current address pointed by the PC will be used.
The S command, when used with no prefixed address will single-step the processor, executing one instruction at a time. All 8502 registers and modified memory locations are updated and the following instruction is printed. The display of the new registers depends on the BEEPER flag in $F9. This flag can be toggled on/off with the D command.
The S command when used with a prefixed address will make this address the new program counter value, without executing any instructions.
The SINGLE STEP command works by inspecting the instruction to be executed and determining where the following instruction is located; it then places a temporary breakpoint at that location. For most instructions this is a trivial process because the next instruction to be executed will be the next instruction in memory. However, for instructions which transfer control by reloading the program counter (e.g., jmp, jsr, rts, branches, etc.), the address of the next instruction must be calculated accordingly.
IMPORTANT: You cannot step through ROM. Hexpert will allow you to step through ROM code, however the program will probably crash right away or something weird might happen. Hexpert will be modified to prevent SINGLE STEPping through ROM code in an upcoming version.
If, while single-stepping a breakpoint is encountered, a message will be displayed and the breakpoint will be removed from the breakpoint table.
HINT: It is possible to single-step through some of CBM's Kernal routine by first transfering the entire ROM Kernal to the underlying RAM, using the T command from the monitor. The T command should look like this: T FC000 FFFFF 0C000 + [RETURN] This will move ROM code in RAM BANK 0. Then using the debugger's K command, switch the ROM off and you will be able to single-step through the pseudo-ROM routines.
Example:
DEBUG> 02000; S set new program counter at address
. 02000 A9 41 LDA #$41 $2000 in BANK 0
DEBUG> S execute the LDA instruction AC = $41
. 02002 20 D2 FF JSR $FFD2
DEBUG> J execute subroutine at $FFD2
. 02005 00 BRK
Command: T
Purpose: top-step through subroutines.
Usage: Tparam
Note: param refers to the number of bytes to skip when setting the return temporary breakpoint.
The T command will only have effect if the instruction at the current PC is a jsr instruction. If so, Hexpert will set a brk instruction after the jsr with an offset of param bytes, where param is a numeric value in the range 0 through 9. Then Hexpert will perform the JMPFAR at PC. What this means is that the subroutine at the current PC will be executed and control will return to Hexpert after the routine. The use of the param parameter is to allow routines which are passed parameters via the return address on stack to be top-stepped too. Here is an example of such a routine:
...
jsr i_DoWindows ; Call the window display routine
table .word WindowTable ; Address to window table
.byte Screen1 ; Screen in which to draw window
done bcc error ; Window display was not successful
...
In this situation, you would use a T3 command so that the return breakpoint would be set at 'done' instead of at 'table'. The J command mentioned earlier is nothing more than a T0 command, provided for practical reasons. Most programmers will make use of the T command, because few programmers use this inline parameter passing technique, but the command is there for your convenience anyway.
NOTE: It is important that the return address on stack corresponds to the correct value of param or else, control will not return to Hexpert, which could have unpredictable results.
In the example above, you would use the T command like this:
. 03000 20 00 C0 JSR $C000
DEBUG> T3 Execute subroutine and set return
. 03006 90 0A BCC $3012 break point at address $3006 instead
DEBUG> of $3003.
Breakpoint Commands:
When debugging a program, it is often desirable to stop program execution at a specific point so that you can check variables, flags or registers, making sure they contain the correct and expected values. The debugger implements this mechanism with breakpoints. A user-defined breakpoint, or breakpoint for short, can be set at a specific point in the program. When the breakpoint is encountered, control is transfered to the debugger, a message is printed, the instruction at the breakpoint is disassembled and the breakpoint is removed from the table, which also means that the original instruction is restored. This current version of Hexpert removes the breakpoint because of memory conflict, but an upcoming version of Hexpert should allow breakpoints to be reused any number of times.
The breakpoint is triggered before the instruction at the breakpoint is executed.
NOTE: You can set up to ten user-defined breakpoints. Care should be taken to avoid setting two breakpoints at the same address. This could have undesirable consequences if the breakpoints are removed in wrong order.
How Breakpoints Work: The Ins and Outs of Breakpoints
The 8502 implements a special instruction called brk (for break) which generates a non-maskable interrupt. The debugger intercepts this interrupt and treats it as a software breakpoint. When you set a user-defined breakpoint, the debugger replaces the data byte at the address with a brk instruction ($00). By going through the debugger, the breakpoints are automatically controlled and managed. Because the debugger saves the byte that was replaced, it is capable of restoring it later on.
However, there is nothing stopping you from manually placing brk instructions in your code using Hexpert's VIEW BYTE option. These brk instructions will actually appear as brk's and will not be managed by the debugger. When one of the these brk instructions is encountered, the debugger returns with an appropriate message. The debugger will not execute or step through a brk instruction.
NOTE: Because breakpoints are implemented by modifying data in memory, they cannot be set in ROM. Any attempts to set a breakpoint in ROM will cause a zero to be written to RAM mapped behind it.
Command: B
Purpose: Set/Remove a user-defined breakpoint.
Usage: [addrexp]Bparam
Note: If addrexp is specified the breakpoint will be set at the corresponding address. If addrexp is not specified, the breakpoint will be removed. The breakpoint affected by this operation depends on the value of param, which must be a decimal numeric value (0-9).
The B command allows you to set user-defined breakpoints in memory. If you specify an address, the breakpoint will be set at this address. If not, then the corresponding breakpoint will be removed from the table. Your determine which breakpoint (out of ten) is affected by specifying param which is a decimal number (0-9).
NOTE: Hexpert will not allow you to set breakpoints in zero page memory and it will not allow you to remove a breakpoint that has not been set already.
Appendix A: Hexpert Messages
Information Messages
These messages will be displayed everytime Hexpert want's to tell you something has beed done.
HEXPERT Vx.x, (c) 1990
BY ADVANCED SOFTWARE SYSTEMS
This message indicates that Hexpert has been enabled. This message appears every time you will type SYS 4864 + [RETURN].
> breakpoint removed
Informs you that a breakpoint has been removed via the REMOVE BREAKPOINT command.
> breakpoint has been set
Informs you that a breakpoint has been set via the SET BREAKPOINT command.
Error Messages
These messages will be displayed everytime Hexpert refuses to do a command because of a certain condition. These messages do not necessarily mean that something has gone wrong. They can simply mean that Hexpert has stopped executing a program because a BRK was encountered.
> breakpoint encountered
A user-defined breakpoint has been encountered during the program execution.
> user brk encountered
A brk instruction was encountered. You should use the brk instruction instead of a rts to exit out of you program.
> breakpoint invalid
An attempt has been made to set a breakpoint in zero page memory ($0000-$00FF). This message will also appear if you try to remove a breakpoint which had not been previously set.
> not a jsr instruction
This message is displayed if you attempt to use the JUMP TO SUBROUTINE or TOP STEP commands on an instruction other than a jsr.
> end of program
This message is displayed if you attempt to single step your program past the last rts command. This can be checked in SINGLE STEP mode by comparing the current value of the stack pointer with its initial value. If the current value is equal to the initial value, the program is at the same level it was when it first started so a rts will not be allowed. This is only a safety feature. The stack can not be checked while the program is in FULL SPEED execution mode, this is why it's important to terminate your programs with a brk instead of a rts instruction.
Appendix B: Hexpert Technical Notes
Debugger Dependency
Hexpert depends on the ROM monitor code at $B000-$BFFF. This should not be a problem, but it explains why the debugger will not work in C64 mode. Hexpert makes as much use as possible of the monitor's own code, and will use some of the monitor's variables. The debugger also uses some Kernal routines (BSOUT, INDFET, INDSTA, etc.). This should not be a problem either.
Off Limits Memory
At no time should the application modify the following memory areas:
1: $1300-$1BFF / BANK 0 (debugger kernal)
2: $FFFA-$FFFF (interrupt vectors)
The application should be careful, as usual, if it needs to modify memory in the range $0000-$0400. This is the C128's operating system variable space. A lot of these variables are only useful for BASIC so then can be tampered with, as long as you restore their original values upon re-entering BASIC.
Miscellaneous
With the ROM bank enabled with the MMU register, any attempt to modify the ROM memory area will actually modify the RAM which is swapped over. This is why attempting to set a breakpoint in ROM will store a $00 (a brk instruction) in the RAM it maps over.
The application can modify the memory map register (location $D500) directly. Hexpert will sense the state and adjust appropriately.
The Hexpert QUIT command assumes that the important system variables in zero page are intact. If they are not, the system may crash, requiring a reset.
Keep in mind that Hexpert preserves the program's state when exiting to the monitor, so it is possible to toggle in and out of the monitor to use some of its more advanced memory viewing commands while executing a program.
Appendix C: Bibliography and Further Reference
Commodore 128 and the 8502 Machine Language
Commodore 128 Programmer's Reference Guide,
Commodore Bussiness Machines, Bantam Books, Inc.,
666 Fifth Avenue, New York, NY 10103 (1986)
This is clearly a "MUST HAVE" book. No C128 programmer should be without it. It contains a bundle of OFFICIAL C128 information and it includes some information on the rather obscure CP/M mode.
Commodore 128 INTERNALS: The Authoritative Insider's Guide,
Data Becker Books, published by Abacus Software, Inc.,
P.O. BOX 7211, Grand Rapids, MI 49510 (1985)
Another "MUST HAVE" book for the serious machine language programmer. It's main interest is obviously the entire disassembled/commented ROM listing of the C128 Kernal (over 200 pages of listing). Besides the ROM listings, this books has a wealth of interesting technical information on the different 128 components such as the MMU, the VDC and the VIC chips.
Machine Language for the Commodore 64, 128, and Other Commodore Computers,
Brady books, published by Prentice Hall Press, New York, NY 10023 (1986)
Written by the Commodore GURU himself, Jim Butterfield, this book is an excellent introduction to the 6502 machine language on Commodore machines. Contains memory maps for virtually all Commodore computers. I highly recommand this book if you are a novice or intermediate machine language programmer.
This is by no means a complete 6502 machine language bibliography, several other good books are available, notably some excellent books from Compute's. Don't forget your old copies of Compute's Gazette, RUN, Transactor, etc. Some of the best machine language tutorials can be found in these monthly magazines.