It is currently Thu Nov 23, 2017 7:41 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Fri Aug 05, 2016 9:31 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5832
Location: Canada
I've usually just ensured that branches don't cross a page with small pieces of aligned code, but I thought it might be useful to have an assert to verify it. Here's code that should do it:

Code:
.macro assert_branch_page label_
   .assert >(label_) = >(*+2), error, "Page crossing detected!"
.endmacro

test:
   assert_branch_page :+
   beq :+ ; .assert should happen if this would cross a page
      nop
   :
   rts


This seems to work fine, but I'd appreciate a second set of eyes on it, just to be sure. Does this look correct to you? Is *+2 before a branch instruction the right value to test against the label?


Top
 Profile  
 
PostPosted: Sun Aug 28, 2016 9:07 pm 
Offline

Joined: Fri Mar 02, 2012 11:10 pm
Posts: 35
Just tested it myself; I believe it is correct.

6502.org says "A page boundary crossing occurs when the branch destination is on a different page than the instruction AFTER the branch instruction", which is exactly what this macro detects.


Top
 Profile  
 
PostPosted: Sun Aug 28, 2016 9:23 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
If the assert comes before the instruction, then yes, I believe you have to compensate for the size of the instruction itself. I've implemented this functionality a bit differently - I have two macros, one for general page crossing checks, which can be used for data tables or anything else that isn't a branch instruction, and another one specific for branches, which outputs the branch instruction itself (so I only have to write the target label once in my source code) and then checks whether the branch will cause a page to be crossed:

Code:
   ;Generates a warning if two address are in different memory pages.
   .macro Assembler_TestPageCrossing _FirstAddress, _SecondAddress
      .ifblank _SecondAddress
         .assert >_FirstAddress = >*, warning, "Unintentional page crossing."
      .else
         .assert >_FirstAddress = >_SecondAddress, warning, "Unintentional page crossing."
      .endif
   .endmacro

   ;Outputs a branch instruction and generates a warning if the destination is in another memory page.
   .macro Assembler_BranchToSamePage _Instruction, _DestinationAddress
      _Instruction _DestinationAddress
      Assembler_TestPageCrossing _DestinationAddress
   .endmacro

Code:
Test:
   Assembler_BranchToSamePage beq, Destination
   ;(more stuff)
Destination:


Top
 Profile  
 
PostPosted: Sun Aug 28, 2016 9:27 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5832
Location: Canada
Thanks for the replies.

In the weeks since I asked this question, I realized that I could just use the macro immediately after the branch instead and not have to do the +2 (and could also just use the same macro for page crossings everywhere, e.g. RAM regions to be indexed).

My question was really just "is the page crossing from PC + 2 of the branch?" Cause a lot of documentation isn't very explicit about it. Makes sense, though. PC gets adjusted by +2 by the CPU automatically, like it would for any 2 byte instruction, and then branch just optionally adds to it,


Top
 Profile  
 
PostPosted: Sun Aug 28, 2016 11:05 pm 
Offline
User avatar

Joined: Sun May 27, 2012 8:43 pm
Posts: 1311
Is it possible to have every global label be automatically checked against this? I expected that ca65 would give a warning if any label crossed a page boundary, given the ruinous behavior when that happens, but if that's not the case then having an assertion for every global label that could be a routine would be nice.

jsr is not jmp


Last edited by mikejmoffitt on Mon Aug 29, 2016 1:40 am, edited 2 times in total.

Top
 Profile  
 
PostPosted: Sun Aug 28, 2016 11:11 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5832
Location: Canada
What do you mean by ruinous behaviour? The only consequence of crossing a page is it takes the CPU 2 more cycles. Unless you're working on timing critical code it doesn't make a difference.

What's a "global label that could be a routine"?


Top
 Profile  
 
PostPosted: Sun Aug 28, 2016 11:33 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
The only "ruinous" thing I can think of related to page crossing is an indirect JMP that loads the destination address from the last byte of a page, because the CPU wraps around to the beginning of the page for the second byte of the address, instead of advancing to the next page.

Other than that, page crossing is hardly a big deal on the NES. Sure you have to avoid it in timed code, but that's hardly a big part of a typical NES game. A simple macro should cover these cases without problems.


Top
 Profile  
 
PostPosted: Sun Aug 28, 2016 11:43 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5832
Location: Canada
tokumaru wrote:
The only "ruinous" thing I can think of related to page crossing is an indirect JMP that loads the destination address from the last byte of a page, because the CPU wraps around to the beginning of the page for the second byte of the address, instead of advancing to the next page.

That generates this warning: "jmp (abs)" across page border


Top
 Profile  
 
PostPosted: Mon Aug 29, 2016 1:37 am 
Offline
User avatar

Joined: Sun May 27, 2012 8:43 pm
Posts: 1311
That's my mistake - I was confused, and thought of jsr suffering from that problem, rather than jmp.


Top
 Profile  
 
PostPosted: Mon Aug 29, 2016 2:58 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5832
Location: Canada
Well, it's also only indirect jmp, which I think is exceedingly rare to fall on a page boundary (there just aren't many relevant use cases), and easily prevented. Direct jmp doesn't have this problem.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: Google [Bot] and 12 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