Yes, using JSL/JML or the f: prefix are safe. They will ensure you get the correct instruction for a far jump.
Otherwise these are automatically selected by whether or not the label is declared :far somewhere
above its usage in the file. I don't really like the conflation of JSR with JSL but there seems to be some precedent for this in older assemblers and reference. (I'd love a directive to disable JSR as JSL.)
There are three ways I know of to declare something as far, using address modifiers:
Code:
; put it in a segment with a modifier
.segment "s" : far
label: ; this label is now a 24-bit address
; use .import, .export, or .global to forward-declare it with a modifier
.global label : far
label: ; this label inherits 24-bit size from its .global declaration above
.proc label : far ; this labelled procedure is now a 24-bit sized address
rts ; be careful if using .smart mode, which will change rts in a far context into an rtl.
.endproc
Because of the one-pass model of ca65, this only works if the address modifier declaration is above the place you used it. Unfortunately, accidentally putting the address declaration
below fails to produce an error for the uses above, and the address gets silently truncated to 16-bits currently. I consider this a bug and have
raised an issue on GitHub to report it.
Also, I strongly advise against using
.org at all with ca65. It turns off most of the linker's capability to do safety checking. As a feature in ca65 it mostly exists to permit use of legacy assembly code that relies on it, but the idiomatic ca65 way to place code is through segments and your linker config.
Incidentally have been reading the ORCA/M manual after koitsu linked it to me. It also recommends against ORG:
"The ORG directive, a relic from the older Apple // machines, is really not needed on this system. It is used to force code to be located at a specified address. We recommend that you not use it at all." This is basically for the same reason, as it is also an assembler with a linker, though in this case much of the link work seems to be done by the Apple II executable format, similar to DOS executables? (I don't know the Apple II territory very well.)
However, what I think I would suggest, at least as far as ca65 goes, is to avoid the "all in one file" model of doing things. If your translation units don't have more than one bank's material in them, they are a lot less prone to this error. I was personally surprised that I'd never run into it, and realized this practice is why; I'm used to this style of organization from C coding, where it was normal to separate your code into multiple files with imports and exports (in C, the header file externs) to manage the things that would connect.
When all your "far" references are imports at the top of the file, there's a lot less chance to mess up the ordering, or have problems with the one-pass model of things.
This got me thinking more about the movable direct page issue. I started an issue thread about this as well at the github:
65816 direct page and data bank assembly directives?However, I raised the issue not really expecting ca65 to ever change in this way, but more as an opportunity to foster discussion about it. I listed the coding practices I use that seem to make it a very manageable issue for me so far, and the change I'm proposing I think is very high impact on the compiler. So... unfortunately the work (especially testing) required vs. what I'd get out of is below my threshold of wanting to undertake it. I'd welcome comments about it, though, which is why I started the issue thread. Can you think of a lower impact way to do it? Do you have other coding strategies that work well? Am I wrong to think it would be a useful feature at all? (I consider myself very experienced with ca65, but not so experienced with 65816, so I'd really appreciate commentary.)
Also, take note that the address and operand modifiers discussed above work for data instructions as well, i.e.
LDA f: is always 24-bit, but regular LDA will do it only if it's already declared as far. By default they will be 16-bit addresses, though, which means you need to ensure the correct DB manually. Again, has the same problem that it won't report an error if your :far appears after instead of before, and trying to mix abs bank-local data fetches with far cross-bank ones or otherwise mixing banks in one file is a bit of a nuisance.