Macros to assert current register size in ca65

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Macros to assert current register size in ca65

Post by tepples »

The ca65 Users Guide lists a pseudo-variable .CPU for use in assertions about the CPU type. But it doesn't list anything for the state of a given CPU type, namely whether a 65816 is in 8-bit or 16-bit mode for the accumulator or index registers. So I wrote some macros to test these. They're useful if you're using smart mode (which tracks 65816 REP and SEP instructions to know which instruction size to generate for immediate operands. It requires the linker script to define a segment called "DEVNULL" that is not written to the output file.

Am I doing it wrong?

Code: Select all

.macro assert_regbits_816 ldr, expected_size
.pushseg
.segment "DEVNULL"
.local Code
.proc Code
  ldr #0
.endproc
.popseg
.assert .sizeof(Code) = expected_size, error, .sprintf("expected %d-bit mode for %s but got %d-bit", 8 * (expected_size - 1), .string(ldr), 8 * (.sizeof(Code) - 1))
.endmacro

.macro assert_a16
  assert_regbits_816 lda, 3
.endmacro
.macro assert_i16
  assert_regbits_816 ldx, 3
.endmacro
.macro assert_a8
  assert_regbits_816 lda, 2
.endmacro
.macro assert_i8
  assert_regbits_816 ldx, 2
.endmacro

; Test cases ;;;;;;;;;;;;;;;;;;;

.out "The following should all succeed"
.p02
assert_a8
assert_i8
.p816
.a16
assert_a16
.a8
assert_a8
.i16
assert_i16
.i8
assert_i8

.out "Six errors should follow"
.a16
assert_a8
.i16
assert_i8
.a8
assert_a16
.i8
assert_i16
.p02
assert_i16
assert_a16
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Macros to assert current register size in ca65

Post by thefox »

Seems like a good way to test it. I'll be probably using this trick if/when I get around to doing some more SNES coding.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Macros to assert current register size in ca65

Post by blargg »

I'm only imagining a use for this in macros. If you want to be sure the assembler is configured for a certain register size for a routine, just set it with .A8, .A16, etc. before the routine's code. If you want to be sure that the register is that size at run-time, an assemble-time macro can't help you; you ned REP and SEP.
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Macros to assert current register size in ca65

Post by koitsu »

I have absolutely no idea what all of that pseudocode is about (nor do I have any idea what ldr does -- there is no such opcode on 65816), nor what it solves. What's the issue?

The ca65 assembler already seems to have brains for knowing what size your registers are at operation-time (by following sep/rep bits as you said). If you want to change the behaviour or override it, then what blargg said is spot on. This is how 65816 assemblers have behaved/worked for years (my own experience being with Merlin 16, ORCA/M, and x816). You use the assemblers' pseudo-ops (ex. .a16) to accomplish such overrides, all with the hope that the programmer knows what they're doing. (Such overrides almost always justify a small comment explaining why it's being done)

(Footnote: not in this thread, but the other -- people whining/crying over the dynamic register sizes on the 65816 need to get over it already, such complaints (at least with me) fall on deaf ears. It isn't ever a problem when writing/creating new code, only when disassembling or reverse-engineering existing binary data. And I'd take the pains of that over the nonsense of most present-day architectures any day of the week.)
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Macros to assert current register size in ca65

Post by tepples »

In the macro, ldr is a macro argument whose value is lda or ldx.

I just wonder what was in that Psygnosis assembler.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Macros to assert current register size in ca65

Post by blargg »

I can understand the motivation for this. The processor has modes, and if you change them at all, you may be in the wrong one when some code is executing. To make it worse, there are two copies of this mode, in addition to the one you expect: the one the assembler is in, and the one the processor is in while the code is executing. These macros at least allow you to ensure the assembler is in the same mode you want, and presumably the programmer has the processor in the same mode as the assembler. The objection to changing the mode is that it has overhead and might require masking things if you're widening any registers.

The above has led me to laying out a "standard" mode to run everything in, and only stray from it where the benefits outweigh the cost. This has some cost in slightly slower/larger code than optimizing register size everywhere and handling all the variations between routines in some globally-optimal way (which would be ripe for hard-to-find bugs).
nocash
Posts: 1405
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: Macros to assert current register size in ca65

Post by nocash »

This thread is confusing. Many directives & variables & macros, and it isn't quite clear to me what tepples was asking for.

The .p02 .p816 directives seem to be selecting 6502 or 65816 mode.
The .a8 .a16 .i8 .i16 directives seem to be selecting 8bit/16bit modes.
I don't know if they do just tell the assembler which mode to use, or if they do additionally produce code (eg. REP/SEP).

But I think tepples already knows that, and he wasn't asking what they are doing, or how to switch between 8bit/16bit modes - but rather how to detect if the assembler is in 8bit mode or 16bit mode.

I can't imagine what tepples meant by "useful if you're using smart mode". But that type of detection might be useful here or there. Like in a macro that shall generate REP/SEP opcodes only if needed (ie. only if the assembler state (and implied: the assumed cpu state) isn't already in the desired mode).
tepples wrote:Am I doing it wrong?
...
.out "Six errors should follow"
If you were getting that six errors (?) then you are probably doing it right.
tepples wrote:I just wonder what was in that Psygnosis assembler.
What Psygnosis assembler? Didn't you refer to something called "ca65"? Or is ca65 a compiler that interacts with the psygnosis assembler?

The term "assert" (and the purpose ".assert " directive) are also confusing me. Maybe my english just too bad to understand the subject :-)
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Macros to assert current register size in ca65

Post by thefox »

nocash wrote:
tepples wrote:I just wonder what was in that Psygnosis assembler.
What Psygnosis assembler? Didn't you refer to something called "ca65"? Or is ca65 a compiler that interacts with the psygnosis assembler?
Psygnosis had a SNES development kit (Psy-Q) with an assembler called ASM658. In another thread somebody mentioned that it had some automation related to checking that the register sizes are set correctly.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Macros to assert current register size in ca65

Post by blargg »

As I understand it (I haven't read tepples' code closely), these are macros to assert that the assembler's current A or X/Y size setting is a particular value. I noticed that the code generates an instruction that generates 2 or 3 bytes of code depending on the mode (and in a dummy segment so it doesn't add anything to the ROM), and has an .assert, which agree. It also has some tests where a concrete failure is an abstract pass. In another thread another assembler is mentioned and I think the question is how/what it did regarding this issue of verifying the assembler mode.

Smart mode is probably where the assembler attempts to adjust its mode to match the code, e.g. it watches for REP/SEP. In this mode, one might not realize the register size changed and thus the assertion is a good way to express and verify the programmer's expectation in the source code.

tepples' approach (perhaps all one can do within ca65's limitations) I don't think allows for anything other than an assertion/error, as the size of generated code can't feed back to deciding whether to generate some code (probably because this could easily lead to feedback loops where the assembler/linker would have to keep re-running).
ARM9
Posts: 57
Joined: Sun Aug 11, 2013 6:07 am

Re: Macros to assert current register size in ca65

Post by ARM9 »

nocash wrote: But that type of detection might be useful here or there. Like in a macro that shall generate REP/SEP opcodes only if needed (ie. only if the assembler state (and implied: the assumed cpu state) isn't already in the desired mode).
I'd rather have it throw an error than trying to write code for me in that case, not only because you'd also need to have the macro restore the processor state at the end with an additional rep and/or sep.
User avatar
blargg
Posts: 3717
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Macros to assert current register size in ca65

Post by blargg »

I just had a realization that was delayed this long because of the premature-optimization disease. My troubled mind sees the register size mode bits and yells "Oh my god, I have to optimize the size at all times or I'm not getting every last ounce out of the processor!" But I just had a flash of insight: these mode bits are something you decide globally based on your overall design. Are you porting lots of 6502 code? Then you probably use emulation mode. Is size critical, and are you dealing with mostly small arrays? 8-bit everything is probably best. Larger arrays, size not critical? 16-bit X/Y. Compiled C code? Asm doing lots of large integer manipulation? Obviously 16-bit A. Basically it's a way to set the overall processor characteristics. Of course you might temporarily change them where it has a significant benefit, but it's not something you change constantly and try to accommodate as if it were just another ever-changing flag.

I know I said that I do the above already, but it wasn't due to the above realization, mostly defeat and acceptance of terrible, dreadful sub-optimality.
Post Reply