Part 5 - Improving the Debugger and More Keyboard Work
This article continues on from Part 4 - Keyboard and Flashing Text.
In getting this far with Meteor's port I've been using ubee512's debugger fairly heavily. Unfortunately, it was still a tedious process and since it looked like some of the upcoming problems were going to be pretty nasty I decided to contact ubee512's developer Stewart Kay about improving the debugger. I've now made a number of changes that will be sent back to Stewart who will consider them for inclusion in the next version. In the meantime, these are the new features I've added to my local build:
- Memory read/write breakpoints - this is an incredibly useful way to find issues (see below).
- Added the ability to step over function calls (--db-step=o);
- Added the ability to step out of a function call (--db-step=x);
- Improved the interaction between the console (where the debugger runs) and the main emulator window so that you don't need to switch back to the emulator for z80 code to execute.
The above combined with a few macros in the ubee512rc config files:
[s] --db-step=1 [o] --db-step=o [c] --db-step=0 [regs] --db-dumpr [x] --db-step=x [t] --db-step=c
and suddenly the debugger becomes pretty powerful and much easier to use.
Fixing the Corrupted Landing Pad Scores
So armed with the upgraded debugger and following my theory of tackling the simplest issues first my next goal was to fix the corrupted score indicators on the landing pads. My idea here was to calculate the memory address of the first landing pad score, and set a memory write break-point to see if I could find the code writing to it.
I grabbed a snap shot of the screen, loaded it into a graphics editor and calculated the character number of the score indicator - row 14, column 14 and converted it to an offset into the video frame buffer = 0xF000 + 64 * 14 + 14 = 0xF38E.
Next I ran up the game, let it start, and then jumped into the console and set a memory write break-point:
ubee512>--db-bp-mem=w,0xF38E ubee512>c 0e5e: ldir t16/21 FLG: --P---Z- AF:0044 BC:0031 DE:f38f HL:3c0f Z80 'Write to memory address 0xf38e' Debugging break point at PC: 0x0e5e 0e5e: ldir <--- ubee512>
So that area of the screen was getting copied from 0x3C0e. Looking back at my annotated asm listing showed that this area was in an area I'd previously figured out to be an off-screen buffer. It looks like the game has two such buffers - one containing the static background and one containing the rendered screen which is then transferred to the real video buffer. So I cleared that break point and set one on the off-screen buffer:
ubee512>--db-bpclr-mem=w,0,0xFFFF ubee512>--db-bp-mem=w,0x3c0E ubee512>c 0e5e: ldir t16/21 FLG: --P---Z- AF:2f6c BC:0031 DE:3c0f HL:400f Z80 'Write to memory address 0x3c0e' Debugging break point at PC: 0x0e5e 0e5e: ldir <--- ubee512>c 22aa: ldir t16/21 FLG: --P----- AF:3104 BC:0001 DE:3c0f HL:17aa Z80 'Write to memory address 0x3c0e' Debugging break point at PC: 0x22aa 22aa: ldir <--- ubee512>
The first stop looks like the background buffer getting cleared using the static buffer. The second stop looks suspicious. Going back to the ASM listing though and there it was - a memory address that I missed in the original conversion. Fixed.
Fixing the Weird Bouncing Flagship
Next I thought I'd tackle the flagship that was appearing the the top left corner:
I tried a similar approach to above but it led to some pretty complex code - I think the core of the game and the graphics rendering code. After about half hour of that I decided to try something else. This time I set a memory read and a memory write breakpoint on the area of memory where the game used to reside - figuring that any other addresses that I missed would end up reading or writing from that area. The game used to reside at 0x4500 and the stack grows down from 0x8000 so:
Ran up the game and immediately hit a break-point - after which it took about 30 seconds to trace back to another missed address. Now it's looking a lot better, with even the little men at the bottom re-appearing.
In retrospect, this is a pretty powerful way to find these issues and wish I had the debugger functionality (and the idea) from the very start.
More Keyboard Work.
In the previous article where I first addressed the keyboard port I mentioned that some of the keyboard handling I temporarily disabled. Since I now had the game basically running it was time to fix that up. In the end this was more an exercise in reverse engineering the code and re-implementing it.
Starting with the 'R' key used to release the ship and to fire the retro rockets. The code was easy to find and this:
LD A,(3804h) AND 04h ; 'R' Key LD B,A LD A,(3840h) AND 80h ; Enter Key OR B LD B,A IN A,(13h) CALL L4C71_sndout CPL AND 13h INC A AND 14h OR B RET
LD A,KEY_R call isKeyDown JR Z,r_pressed LD A,KEY_SPACE call isKeyDown JR Z,r_pressed XOR A RET r_pressed: LD A,1 OR A RET
The arrows keys for left right was similar though a little more complex:
check_left_key: LD A,KEY_LEFT CALL isKeyDown JR Z,left_arrow_pressed LD A,KEY_COMMA CALL isKeyDown JR Z,left_arrow_pressed LD B,0 JR check_right_key left_arrow_pressed: LD B,20h check_right_key: LD A,KEY_RIGHT CALL isKeyDown JR Z,right_arrow_pressed LD A,KEY_PERIOD CALL isKeyDown JR Z,right_arrow_pressed LD C,0 JR keys_checked right_arrow_pressed: LD C,40h keys_checked: LD A,B OR C
I now had a playable game!
Although, on getting the highest score though was presented with this:
Hrm... I reckon that'll be those calls to the TRS80 Basic routines that I mentioned in the first article.
Getting close now (I think).