+  RHDN Forum Archive
|-+  Romhacking
| |-+  General Romhacking
| | |-+  FDS and VBlank
Pages: [1]
Author Topic: FDS and VBlank  (Read 247 times)
KingMike
Guest
« on: March 29, 2007, 09:54:23 am »

I'm work on an FDS game, and I'm trying to figure out how come an extra VBlank check crashes the game.

See, I've added compression to this game to fit the text into the limited RAM space.
Most games I've see just do LDA $2002 : rest of code,
but I've done (Loop: BIT $2002: BPL Loop: rest of code). This game has two text routines I've messed with. One prints one character at a time, the other prints a whole string at once.
I've made the full-string routine wait for VBlank before printing each character.
In places where the full-string code was used, the VBlank check works.
In places where the one-character routine was used, I replaced it with a call to the full-string routine.
With the replacement call, it works without the per-character VBlank check, but crashes with the per-character VBlank check.
(without the per-character VBlank check, it still works if I check VBlank right before the replacement call)
Disch
Guest
« Reply #1 on: March 29, 2007, 01:29:49 pm »

polling $2002 to wait for VBlank is a bad idea for several reasons.... and I'm almost certain at least one of them is the cause of your problem

reasons to avoid it:

- it essentially locks up the CPU so it can do nothing else (can't jump to music driver, can't poll for user input, etc)
- it's unreliable.  $2002.7 is flakey if you read it just as its being set, making it possible to miss frames completely (false negatives)
- it conflicts with NMIs if they're enabled.


I would guess the 3rd point is the one that's giving you problems, but it's hard to say.  The reason why is... if NMIs (or even IRQs) are enabled, your $2002 read loop will be interrupted at some point -- and it's very possible VBlank will be over by the time the game RTI's back.


NMIs are really the only way to go for VBlank waits.  What I normally do in these conditions is I cut off the game's NMI routine by changing the NMI vector to point somewhere I want -- then JMPing to the game's original NMI vector.  The nice thing about the FDS is, the NMI vector is in RAM (I forget exactly where... I would *guess* $DFFA, but you may want to look that up).  So when you want to wait for a VBlank, change that vector to point to your routine.  Then in your routine, do your work, then JMP to the game's normal NMI routine.
tomaitheous
Guest
« Reply #2 on: March 29, 2007, 01:56:28 pm »


 Polling the PPU status port can cause the system to miss an NMI which the program might need for variable updating and such. It'd be better to have code in the NMI routine write to a variable in ram, and just poll that variable - just be sure to reset the variable right after the poll.

 Better yet, this would be ideal (this is what I've done) -

 When your custom routine encounters a compressed stream, set a internal flag that indicates working with in a compressed stream.
 
 Then have a separate pointer into the compressed stream

 Read the character and pass it to the text display routine, increment the internal compressed text pointer, decrement the text pointer ( to keep it pointing to the same text - the beginning of the compressed stream).

 Check to see if the compressed pointer has reached the end of the stream, if so - reset the internal flag, and increment the text pointer passed the compressed stream and reset the internal compressed stream pointer.


This will draw out one character per cycle or per vblank.

-Rich

Pages: [1]  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC