nesdev.com
https://forums.nesdev.com/

ca65 page crossing assert macro
https://forums.nesdev.com/viewtopic.php?f=2&t=14622
Page 1 of 1

Author:  rainwarrior [ Fri Aug 05, 2016 9:31 pm ]
Post subject:  ca65 page crossing assert macro

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?

Author:  furrykef [ Sun Aug 28, 2016 9:07 pm ]
Post subject:  Re: ca65 page crossing assert macro

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.

Author:  tokumaru [ Sun Aug 28, 2016 9:23 pm ]
Post subject:  Re: ca65 page crossing assert macro

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:

Author:  rainwarrior [ Sun Aug 28, 2016 9:27 pm ]
Post subject:  Re: ca65 page crossing assert macro

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,

Author:  mikejmoffitt [ Sun Aug 28, 2016 11:05 pm ]
Post subject:  Re: ca65 page crossing assert macro

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

Author:  rainwarrior [ Sun Aug 28, 2016 11:11 pm ]
Post subject:  Re: ca65 page crossing assert macro

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"?

Author:  tokumaru [ Sun Aug 28, 2016 11:33 pm ]
Post subject:  Re: ca65 page crossing assert macro

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.

Author:  rainwarrior [ Sun Aug 28, 2016 11:43 pm ]
Post subject:  Re: ca65 page crossing assert macro

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

Author:  mikejmoffitt [ Mon Aug 29, 2016 1:37 am ]
Post subject:  Re: ca65 page crossing assert macro

That's my mistake - I was confused, and thought of jsr suffering from that problem, rather than jmp.

Author:  rainwarrior [ Mon Aug 29, 2016 2:58 am ]
Post subject:  Re: ca65 page crossing assert macro

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.

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/