It is currently Tue Sep 18, 2018 8:23 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 13 posts ] 
Author Message
PostPosted: Tue Jul 01, 2014 4:14 pm 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 313
Hello, all. Relatively new to Assembly, but actually very proud of some headway I've made. I'm absolutely positive there are more efficient ways to do what I am doing, but as I learn the code, I am muscling through on my own trying to really understand what it is I am doing.

Thanks to a plethora of online resources, I have been able to create a metasprite made up of four sprites that move together around the room based on joystick input. I am trying to keep them contained within the screen area. Up, right, and down are all successfully working. However, whenever I press Left, the game freezes in the emulator. If I remove the three lines of code that check for position before moving, it works fine. This checking position method works in ALL the other directions, so I'm not sure why left is crashing things.

For brevity, I'll just provide a working piece of the code (for Down) and then the problem piece (left). Let me know if you need more in order to help track down the issue!

Code:
MovePlayerDown:   ;; THIS IS WORKING FINE, as are all directions except left.
   LDA buttons
   AND #%00000100 ;; if down is pressed
   BEQ movePlayerLeft ;; if these things are not true, jump to movePlayerLeft
   LDX $0200       ;;Load the player's Y position into X
   CPX #$D4; compare the Y value to bottom of screen
   BCS movePlayerLeft   ;; if the player is too close to the bottom, skip the rest of the code and jump to movePlayerLeft
   ;;Move Player part...need to move all four sprites
   LDA $0200
   CLC
   ADC #playerWalkSpeed
   STA $0200
   LDA $0204
   CLC
   ADC #playerWalkSpeed
   STA $0204
   LDA $0208
   CLC
   ADC #playerWalkSpeed
   STA $0208
   LDA $020C
   CLC
   ADC #playerWalkSpeed
   STA $020C
   
movePlayerLeft:   ;; You'll notice, this is coded the same way, yet causes the game to freeze.
   LDA buttons
   AND #%00000010 ;; if left is pressed
   BEQ movePlayerUp ;; if these things aren't true, jump to movePlayerUp
             ;;;;;;;;THIS IS THE PROBLEM;;;;;;;;;;;
   LDX $0203            ;; load the x value into X
   CPX #$08             ;; Compare X to position towards the left of the screen
   BCC movePlayerUp  ;; if close to the edge, skip the rest and jump down to movePlayerUp
   ;;;;;;;;;;END PROBLEM;;;;;;;;;;;;;;;;;;;
   ;;Move Player part...need to move all four sprites
   LDA $0203
   SEC
   SBC #playerWalkSpeed
   STA $0203
   LDA $0207
   SEC
   SBC #playerWalkSpeed
   STA $0207
   LDA $020B
   SEC
   SBC #playerWalkSpeed
   STA $020B
   LDA $020F
   SEC
   SBC #playerWalkSpeed
   STA $020F


I realize there are probably many more efficient ways to do all of the above, and I'm very open to anyone providing me info...but I genuinely want to know why this would cause the game to crash in the emulator even if there is a better solution.

Thanks!


Top
 Profile  
 
PostPosted: Tue Jul 01, 2014 4:18 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7519
Location: Seattle
Are you perhaps using NESASM? It's kind of famous for not giving an error on an out of range argument (i.e. the final BCC may be trying to jump more than 128 bytes earlier in the code).


Top
 Profile  
 
PostPosted: Tue Jul 01, 2014 4:22 pm 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 313
Yes, I am using NESASM3. What you're suggesting is possible, I suppose, but I don't think so. Again, this is not the last direction...the two that follow work flawlessly (and jump the same distance in the code), unless I am misunderstanding. Also, when I tried to diagnose the problem by trying to jump down to the end of the directions, it told me it was out of range (and I'm assuming that's what it would do if this were true). Thank you for the suggestion though! And it's good to know that NESASM potentially has that issue, I will watch for it.

Any other thoughts or suggestions, lidnariq or anyone else?


Top
 Profile  
 
PostPosted: Tue Jul 01, 2014 4:37 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10806
Location: Rio de Janeiro - Brazil
I can't catch anything obvious from looking at the code. Which emulator are you using? Does the program crash in other emulators as well? You should try debugging it in FCEUX to see if the CPU is doing what you think it should be doing. Open the debugger and set a breakpoint for, say, reads to $0203. So whenever $0203 is read (which happen right in the middle of the problematic code), the emulator will pause, and from there you can step through the instructions and see what the CPU is doing.


Top
 Profile  
 
PostPosted: Tue Jul 01, 2014 6:39 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1243
Are you open to posting a rom?

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
PostPosted: Tue Jul 01, 2014 9:50 pm 
Offline
User avatar

Joined: Tue Jun 10, 2014 8:15 pm
Posts: 35
Location: Canada
lidnariq wrote:
Are you perhaps using NESASM? It's kind of famous for not giving an error on an out of range argument (i.e. the final BCC may be trying to jump more than 128 bytes earlier in the code).

Wow. :shock: That is just not practical to use without branch error checking. Good to know.


Top
 Profile  
 
PostPosted: Tue Jul 01, 2014 10:35 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1243
Really sure the branching thing has been fixed a long time ago, though. Because I'm sure I'd have encountered it by now, if not, having used it for the last five years. I encourage you to create a test case in the latest version of the software. I'd be happy to be proven wrong. It is open source, the problem could even be fixed if it does still exist. To get off topic, maybe this is why I do not have much interest in releasing software other than games. People will remember and post about the bugs far after they've been fixed. People will make bug reports without having the latest version of the software. And all of that sounds so fun. With games people might lose their save or progress, but not actual work which is easier to deal with.

I don't deny nesasm has other problems, but at least post about those. Or create a test case for this branching error in the program found here. If you can, I'll take my lumps.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
PostPosted: Tue Jul 01, 2014 11:39 pm 
Offline
User avatar

Joined: Tue Jun 10, 2014 8:15 pm
Posts: 35
Location: Canada
tokumaru gave the best advice here. You'll always solve your problems way quicker by simply seeing what value is actually getting loaded with a debugger.


If it is not a branch problem, then maybe some other things you might try/check are:
- check if 'buttons' is really, truly getting updated with the correct bit for the left direction.
- I noticed those 3 lines of code load X. Make sure that you are not depending on X for a different value later in the code.
- make sure you are not getting stuck in an endless loop branching to 'movePlayerUp'. Try hardcoding the branch to be always taken, i.e.:
Code:
   LDX #$07             ;; to always branch
   CPX #$08             ;; Compare X to position towards the left of the screen
   BCC movePlayerUp  ;; if close to the edge, skip the rest and jump down to movePlayerUp

If that works then repeat with a case that will never branch.
Code:
   LDX #$09             ;; will never branch
   CPX #$08             ;; Compare X to position towards the left of the screen
   BCC movePlayerUp  ;; if close to the edge, skip the rest and jump down to movePlayerUp


I can't help you out much more then that as I'm new to the NES.


Top
 Profile  
 
PostPosted: Wed Jul 02, 2014 10:08 am 
Offline

Joined: Tue Jul 01, 2014 4:02 pm
Posts: 313
Alright, the plot thickens...

With some help from Kasumi, I did a little housekeeping with the code. It's a tiny bit cleaner, and I have found the one line that is causing the problem. Setting the carry flag (SEC) in the left direction is what causes the 'crash' (the game freezes, the emulator does not crash...experience with other programming languages makes me think it is getting stuck in a loop).

What's bizarre, my UP direction utilizes the SEC and does not crash. Left, however, crashes. I'll post the updated code snippet for both of those directions:

Code:

movePlayerLeft:
   LDA buttons
   AND #%00000010
   BEQ movePlayerUp
   LDA $0203
   CMP #$08
   BCC movePlayerUp
   SEC        ;; IF I REMOVE THIS, EVERYTHING WORKS FINE...
   SBC #playerWalkSpeed
   STA $0203
   LDA $0207
   SBC #playerWalkSpeed
   STA $0207
   LDA $020B
   SBC #playerWalkSpeed
   STA $020B
   LDA $020F
   SBC #playerWalkSpeed
   STA $020F
   
movePlayerUp:
   LDA buttons
   AND #%00001000
   BEQ movePlayerRight
   LDA $0200
   CMP #$08
   BCC movePlayerRight
   SEC        ;;THIS WORKS WHETHER I REMOVE IT OR LEAVE IT IN
   SBC #playerWalkSpeed
   STA $0200
   LDA $0204
   SBC #playerWalkSpeed
   STA $0204
   LDA $0208
   SBC #playerWalkSpeed
   STA $0208
   LDA $020C
   SBC #playerWalkSpeed
   STA $020C




I'm fairly certain that I understand that generally prior to using ADC, clear the carry flag and prior to using SBC, set the carry flag. I know it is more complicated than that, but that seems to be the general rule for what I have gleaned. And it seems to work fine for UP in the exact same context...but not for LEFT.

Any further thoughts on why this could be the case?

You guys rock.


Top
 Profile  
 
PostPosted: Wed Jul 02, 2014 11:35 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1428
Incidentally, having an SEC immediately after a (not-taken) BCC instruction is indeed redundant - BCC only branches if carry is clear, so if it didn't branch then carry must be set. The fact that removing a single byte causes the problem to go away suggests that this is indeed a problem with trying to branch too far, but we'd need to see the entire program to be able to confirm that possibility.

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
PostPosted: Wed Jul 02, 2014 11:48 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3589
Location: Mountain View, CA
NESASM3 (specifically version 3.1) can generate what is called a "code listing", which is basically an ASCII representation of what the assembled code looks like (including all bytes of opcodes and operands). A code listing would provide the necessary insights to determine if the branches are going to the right place or not. Taken from the NESASM3 docs:

Code:
         -l #   Control output of the listing file:

                    0 - disable completely the listing file even if the
                        LIST directive is used in the input file
                    1 - minimun level; code produced by DB, DW and DEFCHR
                        will not be dumped
                    2 - normal level; only code produced by DEFCHR will not
                        be dumped
                    3 - maximun level; all the code is dumped in the
                        listing file

                The default level is level 2.


I believe the default level (2), ex. -l 2 would be fine. That's dash-lowercase-ELL, not dash-one.

Otherwise I'd consider ceasing use of such broken assemblers; when an assembler itself contains bugs of this nature and doesn't report such errors, that should pretty much be a deal-breaker, i.e. it's time to look at using asm6 or ca65 (pure opinion and not really relevant to this thread per se: I tend to recommend the former, while the latter has lots of capability the learning curve is humongous and you'll spend more time screwing around with the "setup" of the assembler/project than you will actually writing code).


Top
 Profile  
 
PostPosted: Wed Jul 02, 2014 12:54 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10806
Location: Rio de Janeiro - Brazil
I have to agree that this looks like an out of range branch that was assembled incorrectly... It's the second time you say that removing seemingly unrelated code prevents the crash.


Top
 Profile  
 
PostPosted: Wed Jul 02, 2014 1:21 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1243
Quote:
I have to agree that this looks like an out of range branch that was assembled incorrectly...

Still waiting for the test case.

I have the code in hand (as was implied earlier by JoeGtake2's last post, I'm giving some help through PM), and there's definitely some other stuff that needs fixing before I consider this a nesasm failure. Currently, the program wraps the PC across all the RAM (as in $0000-$8000 where the program actually starts) because it hits an RTS before a JSR. That means whatever opcode the RAM for buttons represents could be one that kills the CPU. Or it could be moving left at walk speed changes any of the meta sprites to a value that kills the CPU.

If after fixing the things that cause this, it's still broken I'll be happy to accept it's nesasm AND there will be a test case.

Edit: Fixed, totally wasn't nesasm. One issue was described above, another problem was an RTI after an .org statement after the NMI, instead of an RTI after the NMI. 8-)

Edit2: The technical reason for why this happened, and why adding and removing code made a difference is because nesasm assembles undefined bytes as $FF. $FF is ISC absolute,x. The code ran past the end of the NMI into a long string of $FFs with exactly one $40 (RTI). Recall that the RTI was also after an .org statement, so changing previous code would change its relative position to that code, rather than always having the same number of $FFs between the final instruction and the RTI. Because ISC is absolute, the program could potentially skip the single RTI depending on how many bytes of $FF preceded it. (Running either ISC $40FF,x or ISC $FF40,x). If the RTI happened to be skipped in this manner, the program would run back through $FFFF and start executing the RAM. The opcode $02 (which happens to be what the RAM is set to when only left is pressed on the joypad) kills the CPU.

Edit3: In fact, I just checked. The program would not crash if both left and down are pressed, or if both left and up were pressed. It's just that specifically $02 crashes the CPU.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group