Z88DK and Fuse, list level debugging
Posted: Mon Aug 27, 2018 9:47 am
I posted this to the Z88DK list which is probably where it belongs, but that's a low traffic environment and one or two people here might also find it interesting. So with apologies for the cross post:
Since I started with Z88DK it's become apparent that I've been a bit spoilt over the years with source level debugging. Now I haven't got it I realise how much I rely on it. When my Spectrum program doesn't work the options appear to be to either stare at the C code hoping for inspiration, or single step through the generated Z80 code hoping to be able to follow what's going on. I went looking for an alternative.
The map file produced when you give the -m flag to zcc produces a table of symbols and their addresses in the final executable. Adding the --list option along with the --c-code-in-asm option produce listing files containing the generated assembly language, commented with the original C code. Given that the map contains the addresses of all the functions, and the *.c.lis files contain the offset of each Z80 instruction from the the start of the list file, with a bit of munging it's possible to work out the absolute final address of any instruction in the compiled program.
I wrote a Perl script to do this munging: it takes the map and listing files, works out all the instruction addresses, then concatenates the listing files to generate a single listing file where each line is pre-pended with the instruction address. So it looks, for example, like this:
The "0xXXXX ++" tag on the left side is what my script adds to the single output file - the address of each instruction. I refer to this file as the "tagged source".
I then went to the Fuse emulator debugger source and added a Gtk text widget into the window. The Gtk text widget has the concept of "marks" which allow a point in the text to be identified by a name, a short text string. The widget seems happy to have thousands of these marks, so I wrote some code to load my tagged source file into it, using each line's address tag as a text widget mark. This allows the Gtk text widget containing my tagged source to be able to find and scroll the text to the instruction at any given address.
Final step: the Fuse debugger has a hook which allows the dialog to be updated as the emulator advances the Z80 program counter, so I hooked my Gtk text widget to that with a bit of code which takes the PC register, converts it to a string, finds that string as a mark in the text and scrolls to it. The effect is that as you click the "step" button in the Fuse debugger, the C-and-assembler mixed code in the text window follows the program counter.
Obviously you're still stepping though Z80 instructions, not C code, and you don't get the see the local variables unless you pay attention to the registers or the position in the stack frame they're in. But you do get the context of the C program. You can see the C code the Z80 is working though, and you can see all the symbols which are in that C code, including function names, statically allocated variables and compiler generated labels. It's not hard to see how the Z80 flags are controlling loops, etc.
I recorded a short desktop video, showing it working:
[media]https://youtu.be/TmpHy_x2Fko[/media]
I don't know how useful anyone else might find this, but for me, at my level of experience, I'm finding myself using it all the time.
Fuse is free software and I have a fork on SourceForge. I'm not sure where this is going yet, so can't really provide a static link to the fork. If you want a copy of the Perl script or the Fuse fork, by all means PM me.
Since I started with Z88DK it's become apparent that I've been a bit spoilt over the years with source level debugging. Now I haven't got it I realise how much I rely on it. When my Spectrum program doesn't work the options appear to be to either stare at the C code hoping for inspiration, or single step through the generated Z80 code hoping to be able to follow what's going on. I went looking for an alternative.
The map file produced when you give the -m flag to zcc produces a table of symbols and their addresses in the final executable. Adding the --list option along with the --c-code-in-asm option produce listing files containing the generated assembly language, commented with the original C code. Given that the map contains the addresses of all the functions, and the *.c.lis files contain the offset of each Z80 instruction from the the start of the list file, with a bit of munging it's possible to work out the absolute final address of any instruction in the compiled program.
I wrote a Perl script to do this munging: it takes the map and listing files, works out all the instruction addresses, then concatenates the listing files to generate a single listing file where each line is pre-pended with the instruction address. So it looks, for example, like this:
Code: Select all
...
0x9079 ++ l_gameloop_00129:
0x9079 ++ ;gameloop.c:164: if( in_key_pressed( IN_KEY_SCANCODE_SPACE ) ) {
0x9079 ++ 21 7F 01 ld hl,0x017f
0x907C ++ CD 00 00 call _in_key_pressed_fastcall
0x907F ++ 4D ld c, l
0x9080 ++ 7C ld a, h
0x9081 ++ B1 or a,c
0x9082 ++ 28 0A jr Z,l_gameloop_00104
0x9084 ++ ;gameloop.c:165: game_state->key_pressed = 1;
0x9084 ++ DD 6E FA ld l,(ix-6)
0x9087 ++ DD 66 FB ld h,(ix-5)
0x908A ++ 36 01 ld (hl),0x01
0x908C ++ 18 10 jr l_gameloop_00141
0x908E ++ l_gameloop_00104:
0x908E ++ ;gameloop.c:167: game_state->key_pressed = 0;
0x908E ++ DD 6E FA ld l,(ix-6)
0x9091 ++ DD 66 FB ld h,(ix-5)
0x9094 ++ 36 00 ld (hl),0x00
...
I then went to the Fuse emulator debugger source and added a Gtk text widget into the window. The Gtk text widget has the concept of "marks" which allow a point in the text to be identified by a name, a short text string. The widget seems happy to have thousands of these marks, so I wrote some code to load my tagged source file into it, using each line's address tag as a text widget mark. This allows the Gtk text widget containing my tagged source to be able to find and scroll the text to the instruction at any given address.
Final step: the Fuse debugger has a hook which allows the dialog to be updated as the emulator advances the Z80 program counter, so I hooked my Gtk text widget to that with a bit of code which takes the PC register, converts it to a string, finds that string as a mark in the text and scrolls to it. The effect is that as you click the "step" button in the Fuse debugger, the C-and-assembler mixed code in the text window follows the program counter.
Obviously you're still stepping though Z80 instructions, not C code, and you don't get the see the local variables unless you pay attention to the registers or the position in the stack frame they're in. But you do get the context of the C program. You can see the C code the Z80 is working though, and you can see all the symbols which are in that C code, including function names, statically allocated variables and compiler generated labels. It's not hard to see how the Z80 flags are controlling loops, etc.
I recorded a short desktop video, showing it working:
[media]https://youtu.be/TmpHy_x2Fko[/media]
I don't know how useful anyone else might find this, but for me, at my level of experience, I'm finding myself using it all the time.
Fuse is free software and I have a fork on SourceForge. I'm not sure where this is going yet, so can't really provide a static link to the fork. If you want a copy of the Perl script or the Fuse fork, by all means PM me.