SEGA Genesis: Debugging
Debugging SEGA Genesis code can be tricky, as there currently isn't an all-in-one IDE that allows step debugging and memory inspection.
Most of these features are available in emulators, though, and different emulators are suited for different tasks.
It is possible to debug your ROM in the multi-system emulator MAME with symbols generated from your code, and it will be explained below how to do this. However, MAME lacks sophisticated visualization of graphics memory, and inspecting or modifying other parts of memory is confusingly organized. Other emulators might be a better choice for debugging graphics issues.
Debugging the state of the VDP graphics chip and VRAM can be performed in the Regen and Exodus emulators. Exodus has a lot of debugging features, but Regen is more lightweight and can be used effectively for iterative work, so they might be useful in different situations.
First, we will look at how to debug ROMs in MAME.
MAME Debugging
If you require step debugging of Genesis ROMs and want symbols to help navigate the code, MAME is a decent choice. First off, we will look at starting the MAME debugger.
If you invoke MAME like this, you will get a debug window:
mame64 genesis -debug -dfontsize 11 -window -cart myrom.gen
The disassembly will point to the entry point specified in the ROM header, and execution will start out paused.
You can step through the code with F11. When debugging interrupts, it can be useful to use F7 to run until the next interrupt.
The main debug window shows beamx
and beamy
, which is the horizontal and vertical position of the TV electron beam, useful for figuring out issues with hblank and vblank interrupts.
Below are all the registers, including the program counter (PC) and the stack pointer (SP/A7).
Ctrl+M opens a new Memory window, where memory can be viewed and edited. The drop-down menu selects which memory to inspect. This list has some confusing and non-functional entries, but a few useful ones are:
RAM : memory/:maincpu/0/00e00000-00e0ffff
CRAM : Sega 315-5313 Megadrive VDP:/gen_vdp/0/m_cram.get()
VRAM : Sega 315-5313 Megadrive VDP:/gen_vdp/0/m_vram.get()
ROM : Region ':mdslot:cart:rom'
A few MAME debugger hotkeys:
F10 Step over
F11 Step into
F7 Run until interrupt
Ctrl-M Show memory
And commands:
go [ADDR] Run until reaching ADDR
help The most important command of all
Even though MAME has a disassembly view, debugging your ROM can still be confusing, because the disassembly is a direct translation of the machine code in the ROM, which is similar to, but not the same as, your assembly source code. First of all, all labels are missing, so you'll have to recognize the code itself without the context of naming. Secondly, VASM and other assemblers slightly modifies the instructions used from the ones written in the code, if there are obvious candidates for optimization, e.g. the MOVE instruction can be modified to a MOVEA or MOVEQ instruction, depending on the arguments. Finally, the emulator disassembler can't really know whether a block of memory contains code or data, so data will be shown as code, and to compound the confusion, machine code is ambiguous: the same bytes can be disassembled to different instructions, depending on where the program counter is supposed to point inside the memory.
Dedicated debugging tools often support loading symbols for a binary from an external file, such as a .PDB file. Next, we will look at a way to show symbols from your source code in the MAME disassembly window.
MAME Disassembly with Symbols
To show symbols from your code in the MAME disassembly window, we can use a VASM assembler program lists and the MAME debug comment feature, along with a small translation script.
First off, comments can be added to instructions in the MAME debugger with this command:
comadd [addr],comment
and viewed in the disassembly by pressing Ctrl+N
.
To automate creating comments, we can use the VASM list file feature. If you run VASM like this:
vasm -L myrom.lst -Fbin mycode.asm -o myrom.gen
VASM will generate myrom.lst
, which has a full program listing with extra metadata. At the end of myrom.lst
is a list of symbols:
Symbols:
vblank LAB (0x2bc) sec=CODE
hblank LAB (0x318) sec=CODE
EntryPoint LAB (0x210) sec=CODE
rom_header LAB (0x0) sec=CODE
...
This list has (label,address)-pairs that we can convert to comments in MAME.
The following Ruby script mamelabels-vasm.rb
generates a MAME debugger script from 'myrom.lst':
lines=File.readlines("myrom.lst")
mode=:skip
lines.each do |line|
if line == "Symbols:\n" then
mode=:symbols
end
if mode == :symbols then
if line.include?("LAB")
words = line.split(" LAB ")
addr = words[1][3..-2].to_i(16).to_s(16)
puts "comadd #{addr},#{words[0]}"
end
end
end
When you run
ruby `mamelabels-vasm.rb` > mamesymbols
'mamesymbols' will contain a list of MAME comment commands:
comadd 2bc,vblank
comadd 318,hblank
comadd 0,rom_header
comadd 210,EntryPoint
Now, we can start MAME using this command:
mame64 genesis -debug -dfontsize 11 -debugscript mamesymbols -window -cart myrom.gen
We can now press Ctrl+N
in the disassembly window and we will have our labels listed to the right of the disassembled instructions.
To make this easy to use, we can make a BAT file that assembles, creates the MAME symbols, and starts MAME in debug mode with symbols:
set MAME_OPTS=-debug -dfontsize 11 -debugscript mamesymbols -window
vasm -quiet -L myrom.lst -Fbin mycode.asm -o myrom.gen
ruby mamelabels-vasm.rb > mamesymbols
mame64 genesis %MAME_OPTS% -cart myrom.gen
MAME is good for debugging certain issues, but for debugging SEGA Genesis graphics, Regen or Exodus might be better choices.
Debugging Graphics with Regen
Regen is a emulator with graphics debugging functionality.
While working on some scrolling code, I encountered a VDP bug that was tricky to track down.
I was trying to set the VDP register $0D
(HScroll) to the value $34
, and had accidentally written:
move.w #$8D43,vdp_control ; set VDP reg. $0D = $43
See the problem?
It should have been this:
move.w #$8D34,vdp_control ; set VDP reg. $0D = $34
Debugging this using mednafen or MAME was difficult, and Regen was a better choice. It has a VDP debug view that was very informative, as it shows the values of all VDP registers. Now I could easily see that register $0D
(shown as #13
) was set to $34
instead of $43
.
Debugging with Exodus
Exodus has a extensive suite of debugging windows, including disassembly, RAM viewer/editor, VDP register viewer/editor, VRAM pattern viewer, and more.
The emulator is very useful for debugging, even if it could benefit from a bit more online documentation.
Debugging with Mednafen
mednafen can also be used for basic debugging. Starting mednafen from the command-line with the debugger enabled and paused on the first instruction can be done like this:
mednafen -debugger.autostepmode 1 roms\test1.gen
A few important mednafen debug commands:
R Run
S Step
Up/Down, Page Up/Down Navigate code
Space Set breakpoint
Alt+1 CPU debugger view
Alt+3 Memory view
See Mednafen Debugger Documentation.
Debugging with BlastEm
BlastEm is very accurate emulator with some commandline-based debugging functionality.
After loading a ROM, you can press u
to pause and enter debug mode.
In the command-line, you can now use the following commands:
vr - print VDP register info
vs - print sprite list
c - continue running game
q - quit
See README.txt
in the BlastEm install directory for more information.
References
Emulators:
- MAME - Multi-system emulator, emulates thousands of systems
- Exodus - Modular emulator with a lot of debugging functionality
- Regen - Genesis emulator, with graphics debugging functionality
- mednafen - Great multi-system emulator, currently the most accurate PSX emulator
- BlastEm - Open source, accurate emulator
Tools:
- vasm - Open source multi-CPU assembler