65816: Debugging Code

I haven’t written much about debugging yet, but tools to help debug my code have been essential to my system development. I started out with the simple Ben Eater 6502 build where debugging consisted of repeating a cycle of write code, assemble and burn it to an EEPROM, and test the system for proper operation, maybe with some output to the LCD.

In my builds since, automating the code assembly into my editor and using a ZIF socket greatly sped up this cycle. I could turn around a new code sample in about 10 seconds. But that didn’t really help knowing what was going on with the code in detail such as being able to examine registers or memory during execution, set breakpoints or step through code.

In my second build, I started developing a monitor program that would allow me to do just that, as well as to upload code over a serial connection to memory for testing. I found that this development cycle still took too long though as uploading the file actually took longer than what I finally got to with the write/burn/test cycle.

It was about this time, when looking for ideas for an operating system I came across Py65, an emulator for 6502-based systems. It has the ability to set breakpoints, step through code, and examine memory and registers during code execution. To be honest though, I still found it easier to just continue with my old routine but replacing the EEPROM burn part with loading the code into the emulator. That was even faster than the burn as it could be done with a batch file.

I didn’t care much for adding breakpoints by typing in addresses and examining memory took a lot of typing as well. This is when I discovered I could debug the emulator in Visual Studio Code, using its superior debugging interface to set breakpoints, step through code and watch specific registers and memory locations.

Debugging Python emulator in VSCode

This got me through development of my Forth operating system for the 6502 and porting it to the 65816. It had problems though. It was slow and you were actually setting breakpoints on and stepping though the Python emulator code. To work with your 65xx source code, you had to set one breakpoint in the emulator code to break when the program counter was at the desired source location and when it was hit, you’d set another breakpoint in the emulator step function to single step through your code. Lastly, none of this was linked to the 65xx source code. You had to manually follow along with a listing file. All of this recently changed when I learned that VS Code can do so much more.

VS Code can attach directly to the Python emulator

Starting up my Forth operating system in VS Code was slow, even with the changes I made to the emulator that I discussed in 65816 Emulator – Threading in Python is Very Slow. Loading and processing the several kilobytes of Forth code that comprises part of my operating system took about two and a half minutes running the emulator in the VS Code Python debugger. Standalone, the emulator did this in under 15 seconds. In researching VS Code debugging capabilities though, I discovered that you could attach VS Code to an already running process. Bingo, I could start my emulator up normally in 15 second and then attach the VS Code debugger for a much faster debugging experience. But VS Code could still do more.

Debugging 65xx source code with VS Code

A recent post over on 6502.org introduced me to Microsoft’s Debug Adapter Protocol and the VS Code Mock Debug Extension. A debug adapter connects VS Code to an emulator. Mock Debug provides a basic debug adapter and mocks up a simulated emulator for testing it. It’s intended to help kick start developing a debug adapter for your own emulator. The problem was modifying my emulator for the protocol, a message-based construct, would be a significant effort. I found that the mock debug adapter was pretty complete though and the simulated emulator easily modified to simulate the 65816.

It took me about a day to translate the core part of my Python 65816 emulator to Typescript, the language Mock Debug is written in. Other languages, including Python are possible but would take more effort to mockup a working version of my emulator. Even with that minimal effort the debug experience is vastly superior. I now can set breakpoints and step through the source listing directly, see changing register values (and other memory locations) each step, use the VS Code expression evaluation and watch features and see a call stack.

Debugging 65816 assembly in VSCode

Some of this will take a bit more coding to refine, but so far looks very promising. And it seems very fast. Searching through the source file, which is over 350 kilobytes, for the specific instruction being executed is almost instantaneous. It’s not all roses though as Typescript is very different from Python and some Python features aren’t fully supported. In porting to Typescript, I had to make a number of modifications in addition to simply modifying for language syntax.

Also, what I’ve done so far isn’t a standalone emulator, but a simulated one that runs only in VS Code. I find that only about 50% or so of my testing is done in VS Code. The rest I use the emulator as a standalone application, avoiding the debugging overhead. I supose this might be possible in VS Code as well as you can run Python at least withing VS Code without debugging, but I haven’t tried it with Typescript. I’ll need to decide whether to leave the emulator as a VS Code app, create a separate Typescript based emulator, or create a debug adapter for the Python based emulator. I’m not sure where I’ll end up, but it should be fun getting there.

Leave a Reply