Jump to content
IGNORED

Debugging my game!


Recommended Posts

OK I''ve been fixing the bugs in my abbuc game Ski-It and have a couple of strange ones; they may turn out to be something stupid but after a lot of investigation I've drawn a blank so wonder if they are something technical that I'm unaware of:

 

Bug 1 - Intermittent - space appearing on my message bar "Press Start to continue", only on the first time this screen is shown - I put a break point in immediately after the message is shown and it had happened. The source message is not corrupted as it shows the next time fine. The message display routine is good as far as I can see and works with everything else too. It does seem to move around (see screenshots). It does seen to vary in position but only within a few bytes. The displayed message is 40 chars long and includes the inverse spaces (yellow).

 

Previously it was appearing towards the right side of the message so maybe this indicates something to do with my codes position in RAM which obviously changes as I make changes, however the message BAR has been fixed in ram at $9000 throughout.

 

Bug 2 - Always - DLI colour cycling of score bar (bottom of screen) stops when code reaches loop to read console keys; colours cycle all the time the screen is active / calculating and displaying the line items and points (there are delay loops present between these displays so may only cycle then) but then stops.

 

In both cases this screen has a DLI at the top and another above the yellow/brown message bar, maybe it's something to do with this / DLI / VBI timing?

 

Hope this makes sense!

Any thoughts welcome :?

post-19705-0-32936600-1534498321.png

post-19705-0-83130100-1534498446.png

Link to comment
Share on other sites

I take it you're not using CIO for text output? Cursor artifacts can occur when doing CIO stuff.

 

Colour cycling - it looks like your screen is taller than standard - remember that the VBlank processing begins at the end of the 240 scanline normal possible display. In theory if the VBI is fairly long, the top DLI could trigger before the bottom one has finished processing if the VBlank has interrupted the bottom DLI.

Link to comment
Share on other sites

Thanks for the altirra debug tips I haven't done much with it before apart from set a breakpoint on an address, I try to do everything on the Atari so my breakpoints are usually a routine to show something on screen and wait for joystick movement etc!

 

Ok guys, humour me... I think the two issues are related!

1. The message display routing has a feature to skip over any "Z"s in the message text, so I can mask out sections. This works fine but it does use the X register as the counter for the loop...

(the save/load message was just a test to see if there was other corruption on the 2nd line so no CIO here)

 

2. The reason why the round score colour cycles during the screen build/scoring and not during the console loop is that the delay routines between the line scores cycle X (and Y). DLI2 is picking up this change to X and processing it.

 

 

The VBI/DLI code is roughly as below:

 

VBI
Sets DLI1
Sets background color

DLI1
Stores A,X,Y to DLISAVEA,X,Y
various text colours/effects
Loops while VCOUNT <92
Sets DLI2
JMP QDLICODE

QDLICODE
Restores A,X,Y
RTI
>>>
DLI2
; sets colours for status bar
STA WSYNC
LDA $EA
STA COLPF1
LDA $E2
STA COLPF2
;
; ***this bit***...
DLI2LOOP
INX
STX COLPF0 ; "score"
LDA VCOUNT
CMP #120
BCC DLI2LOOP
;
STA WSYNC
JMP QDLICODE
<<<

 

So DLI2 is changing the status bar colours but is not reaching/doing the loop stage as I'm wrong with the vcount value? Perhaps it's not even completing this processing and sometimes increasing X which is effecting the message display part? I thought vcount was 120 end of screen but as I've got a longer dlisplay list this is incorrect?

 

Mapping has vcount for PAL 155 and NTSC 130. As a test I tried setting these maximums on the main title screen's DLI loop. It locked up as these values were too large for the screen size? For a vcount loop do I need to ensure it's before the last shown line / vcount does not carry on to these maximum values?

 

Good Morning :-D :-o

 

[edit] having a quick look ay the display list:

I think I have 193 scan lines above the message bar, the message bar is another 31 making a total of 224 so vcount max is half of that 112?

Edited by therealbountybob
Link to comment
Share on other sites

Does your DLI2 store A,X,Y ? You are rapidly change COLPF0 colour (severa times per scanline)... why is the STA WSYNC out of loop? (I don't know how the color cycle is supposed to look like)

 

IMHO screen starts at VCOUNT 4 maybe? Similar like PMGs has 8 scanlines above screen and 8 below (8+240+8=256).

Link to comment
Share on other sites

2. OK all it takes is a bit of public humiliation to figure things out, so forget my theories the DLI is working correctly, X is stored and recovered by the DLI so it's not colour cycling as I expected. I'll add and INX to my console loop in the main code as well and that should fix that one. :dunce:

 

so this leaves

1. That space business on the message bar - so it looks like something is increasing Y (not X!) to skip displaying a character (there are no Z's in the message). The P of "Press Start" should be under the G of "Challenges" so it's definitely increasing Y somewhere?!

post-19705-0-93107000-1534593543.png

 

The message display code (typed here)

 

SHOWMSGLOOP ; Y is 0 to start with

LDA (MSGSOURCEPTR),Y ; message text

CMP #$3A ; "Z" masked char

BEQ SHOWMSGLOOP1

;

STA (MSGDESTPRT),Y ; status bar

;

SHOWMSGLOOP1

INY

CPY BARMAX ; (set to 40)

BCC SHOWMSGLOOP

RTS

Edited by therealbountybob
Link to comment
Share on other sites

Waiting on an exact VCount value can be dangerous since you might miss it due to an interrupt. Much better to do a BCS comparison which is a >=

 

And not forgetting the VBlank will occupy some values always. Sometimes an alternate strategy like just waiting for the low byte of RTCLOK to change might be better.

  • Like 1
Link to comment
Share on other sites

The VBI/DLI code is roughly as below:

 

VBI

Sets DLI1

Sets background color

 

DLI1

Stores A,X,Y to DLISAVEA,X,Y

various text colours/effects

Loops while VCOUNT <92

Sets DLI2

JMP QDLICODE

 

QDLICODE

Restores A,X,Y

RTI

>>>

DLI2

ALSO Stores A,X,Y to DLISAVEA,X,Y

; sets colours for status bar

STA WSYNC

LDA $EA

STA COLPF1

...

;

; ***this bit***...

DLI2LOOP

INX

STX COLPF0 ; "score"

LDA VCOUNT

CMP #120

BCC DLI2LOOP

;

STA WSYNC

JMP QDLICODE

<<<

To recap #2 was not a problem, I've now got some nice silver text on the bottom bar. #1 is a problem. I think my DLI above is the issue, either the storing and loading of the registers on both DLIs or the way I'm holding up the DLI using the VCOUNT loop to get a gradiated text effect.

 

As well as the routine skipping an X value for the message display, these screenshots show X is affected at other times during the screen build - the blank section is an X loop and the corrupt characters are meant to be a space that is in the Accumulator.

 

To alleviate this I've diabled the DLI until I've built the screen and this seems ok but I'm concerned that it may effect the results part where I want the screen on. Perhaps I'm doing things illegally or have a timing issue with the DLIs?. Please can someone enlighten me? ;-)

 

post-19705-0-46260900-1535195478.pngpost-19705-0-70184800-1535195483.png

Link to comment
Share on other sites

I would switch back to pushing A/X/Y onto the stack instead of using variables until your DLIs are actually timing limited. Using static variables to save registers means that if there is anything wrong whatsoever with your display list timing and your DLIs overlap you will get register corruption. Most common way this happens is accidentally switching in a new display list mid-frame. With stacked registers the nested DLIs can be resolved and your program won't break.

  • Like 2
Link to comment
Share on other sites

I would switch back to pushing A/X/Y onto the stack instead of using variables until your DLIs are actually timing limited. Using static variables to save registers means that if there is anything wrong whatsoever with your display list timing and your DLIs overlap you will get register corruption. Most common way this happens is accidentally switching in a new display list mid-frame. With stacked registers the nested DLIs can be resolved and your program won't break.

Thanks phaeron I will put that back. Please can you explain this bit (in bold) or how I would avoid doing this?

Link to comment
Share on other sites

If you switch DList using the shadow registers there's next to no chance of corruption - though to be safe if you're in an unknown scanline situation you should do SEI/CLI either side of the change.

If you change DList using direct write to Antic then you should definitely not do it mid frame unless you have the specific reason of sending the DList elsewhere.

The "advantage" of writing to the pointer directly like that is that you get the same effect as the jump DList instruction without getting a blank line.

  • Like 2
Link to comment
Share on other sites

The key to doing a clean screen switch is to change everything in vertical blank -- and by everything, I mean everything. The OS shadow registers help switch the display list cleanly, but their usefulness is reduced by not having all registers shadowed and sometimes skipping the shadow register update. DLIs make doing this safely more complicated than the plain screens that the OS normally deals with.

 

As an example of how things can go wrong, here's an example I recently debugged in a demo:

  • DMACTL, SDMCTL = 0
  • SDLSTL/SDLSTH = new display list
  • SDMCTL = $22
  • NMIEN = $C0

Basically, turn the screen off, queue a new screen with the shadow registers, and turn on DLIs for when it swaps in. Seems safe, right? Nope, because of a subtle issue in ANTIC: DMACTL bit 5 doesn't enable the display list, it enables the display list fetch. The display list is actually running all the time. That means that if the last display list instruction fetched had bit 7 set, the display list is trying to trigger DLIs, even if DMACTL=0 and nothing is being fetched by ANTIC. When the write to NMIEN happens mid-frame, the DLI goes hot immediately in an unexpected place on screen and fireworks ensue.

 

The other problem with the shadow registers is that the OS can decide to skip the shadow update randomly based on what gets interrupted, so you can't rely on the new values being swapped in on the next frame. Some code tries to check for RTCLOK ticking, but that's wrong since RTCLOK is updated in unskippable stage 1. That's a problem when you need to update other unshadowed registers like NMIEN in sync, or reuse the memory from the old display list.

 

The best solution I can think of at this point is to not depend on the OS to update the hardware registers. Instead, wait for vertical blank either by VBI handler or polling for vertical blank. Then, while safely in vertical blank, update both the shadow registers first and then the hardware registers in one go. This avoids any issues from mid-screen changes and from the OS delaying the hardware register updates. Shadow registers need to be written first if polling VCOUNT in case VBI stage 2 runs in the middle of the update.

  • Like 5
Link to comment
Share on other sites

Another thing, not sure if mentioned - if your Stage 1 VBlank runs too long the shadow updates can occur during the active screen which = bad things can happen.

For the purpose of a game, really IMO your best bet can be to just do away with the OS VBlank - take over the immediate vector and do everything yourself.

You can sufficiently streamline code such that checking for masked IRQs and CRITIC could be bypassed - ie skip stuff like software timers and reading unused controllers. If you want to do SIO, just switch back to the default vectors for the duration.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...