SNES register sizing schemes (65816 M and X)

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.
furrykef
Posts: 35
Joined: Fri Mar 02, 2012 11:10 pm

SNES register sizing schemes (65816 M and X)

Post by furrykef »

I'd heard that what a lot of 65816 programmers do is they usually keep the M flag 8-bit and the X flag 16-bit. I found I rarely need 16-bit indexing and started to ponder whether this might be the wrong way around, so last night I rewrote my current projects to default to 16-bit M and 8-bit X. (This actually went pretty quickly.) And... I'm not convinced that this method is any better or worse. It seems the hardware is screwy enough that both schemes are about equally bad.

Let's have a look at the implications of both schemes...

8-bit M, 16-bit X:
  • May have to toggle the size of M more often, which can be bug-prone
  • Instructions such as TAX, TAY will be 16-bit moves while X is 16-bit, and it's easy (especially for 6502 coders) to forget to clear the upper byte first
16-bit M, 8-bit X:
  • Encourages the use of 16-bit vars where 8-bit vars will do (slightly larger and slower code)
  • Can't use STZ for 8-bit values
  • Sometimes I find myself deliberately loading 8-bit variables into my 16-bit A, knowing that I will soon TAX or TAY and chop off the upper byte. I'm not sure this is good practice. I do use Hungarian notation for 65816 ASM code, so it's pretty obvious when I'm doing this.
So my impression is the first scheme results in slightly smaller and faster code, but it has slightly more opportunities for gotchas that could add hours of debugging time. Of course, bits of code where every cycle counts can still be written to use whatever scheme is appropriate, so I don't think the performance hit is a significant concern.

Thoughts?
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES register sizing schemes (65816 M and X)

Post by psycopathicteen »

I do almost everything with 16-bit accumulators and index. During vblank I mainly deal with writing to hardware regs that are mixed sizes, so I use mixed sized accumulator and index.
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Re: SNES register sizing schemes (65816 M and X)

Post by Bregalad »

I am no 65c816 coder so I don't know much, but what is the argument against having 16-bit accumulator *and* index registers most of the time ? If this is a 16-bit CPU, normally most variables and registers should always be 16-bit, exept in rare cases where a smaller size is required, such as arrays with lots of data, which must be 8-bit, or communication with hardware registers. In those cases you could either do AND/OR trickery or shortly turn a register into a 8-bit time before returning to normal, depending on which one is more efficient.
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES register sizing schemes (65816 M and X)

Post by psycopathicteen »

such as arrays with lots of data
Which can still be 16 bit, as long as you're not running out of memory.
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: SNES register sizing schemes (65816 M and X)

Post by Khaz »

I use both ways. Generally speaking I default to keeping both at 16-bit unless I have to do otherwise. When I need an 8-bit register, which I choose depends on which register size I need two of and whether I will be doing any adc/sbc or other A-only instructions. I'd say I use both equally as much and just keep very rigorous track of my register widths.

This is coming from the perspective of someone who has done very little optimizing so far so take it with a grain of salt.
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES register sizing schemes (65816 M and X)

Post by psycopathicteen »

Not only do I program almost everything in 16-bit mode, but I also do almost everything in bank $80 too.
93143
Posts: 1371
Joined: Fri Jul 04, 2014 9:31 pm

Re: SNES register sizing schemes (65816 M and X)

Post by 93143 »

So far I've mostly just been coding graphics tests. I find it's useful to be able to quickly stz to an 8-bit PPU register, so I use 8-bit A and 16-bit X/Y. This is also useful for DMA subroutines, since you can pass two 16-bit numbers and an 8-bit number (actually, I think this is probably why I started off with this combination, even though I don't use subroutines any more). And it strikes me that it could be useful to have some indexing capability without losing the ability to load and store both data sizes. There are exceptions, of course - for instance, writing to (especially zeroing) pairs of adjacent PPU registers in a time-critical H-IRQ while deliberately not using X or Y so as to save on stack operations... bit of an edge case, perhaps...

In the few more game-like bits of code I've done, I find a 16-bit accumulator to be a good idea, since you want to be able to do math with larger numbers.

When I coded an overlay renderer for my title screen mockup, I ended up doing the bitwise logic section with 8-bit A and the actual data combination with 16-bit A. X/Y stayed 16-bit, because I needed to be able to index within the source and destination graphics buffers. (It seems to me that this could be a more general result; large arrays of object parameters, for instance, could easily exceed 256 bytes. On the other hand, the OP says this sort of thing doesn't happen much, and people wrote games on the NES somehow...)

Basically, if I want something to execute quickly, I try to optimize the register size for maximum speed. It may be helpful that I don't seem to care how long this game takes to write didn't start on 6502; 65816 is the first assembly language I learned, so the variable register sizes are a fundamental part of my understanding rather than an annoying hack I keep forgetting about.

That said, I don't believe I've ever used 8-bit X/Y, though that may change as I start writing more game engine code...
psycopathicteen wrote:I also do almost everything in bank $80 too.
Ah, FastROM. I do that too. It's a bit of a pain getting my ancient copy of WLA DX to actually land on the correct bank, but once it's done it's done...
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: SNES register sizing schemes (65816 M and X)

Post by Near »

I always keep 16-bit index registers, and I toggle freely and constantly between 8-bit and 16-bit accumulator.

I am very resentful that we didn't get a pipeline fetcher and a 16-bit prefix byte so that you could use both modes without messing with rep/sep, and constantly have to use php/plp (or have a rigid ABI)
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES register sizing schemes (65816 M and X)

Post by psycopathicteen »

93143 wrote:
psycopathicteen wrote:I also do almost everything in bank $80 too.
Ah, FastROM. I do that too. It's a bit of a pain getting my ancient copy of WLA DX to actually land on the correct bank, but once it's done it's done...
Not only that, but I rarely touch the bank register at all.
93143
Posts: 1371
Joined: Fri Jul 04, 2014 9:31 pm

Re: SNES register sizing schemes (65816 M and X)

Post by 93143 »

You mean the program bank register? I don't either, but I assumed it was because my programs are all small, so there's no point putting anything but data (and sometimes not even that) anywhere outside the first bank. But I code without subroutines, for speed, and I think I prefer to generate multiple specialized routines rather than generalize a single routine at the expense of speed, so I fully expect to use more than one bank for code in the finished game (if it ever gets finished...). The official GSU map seems to have 16 Mb of LoROM from $80-$BF and 32 Mb of HiROM from $C0-$FF, so I think that's probably a reasonable way to divide up code and bulk data...

I have used the data bank register, most notably in that overlay renderer. It took up a sizeable chunk of WRAM, and using 24-bit addressing for the whole thing was just not going to fly...
UnDisbeliever
Posts: 77
Joined: Mon Mar 02, 2015 1:11 am
Location: Australia (PAL)
Contact:

Re: SNES register sizing schemes (65816 M and X)

Post by UnDisbeliever »

My code uses the following three schemes

8 bit A, 16 bit Index: Used for Setup, PPU setup, register manipulation, text routines.
16 bit A, 16 bit Index: Used for physics, tilemap manipulation, pointer manipulation, entity/object manipulation code.
16 bit A, 8 bit Index: Used in the occasional VBlank routine.

I tend to use the method that seams faster in my mind.

I also ensure that a routine exits in the same register sizes as it entered on.

byuu wrote:I am very resentful that we didn't get a pipeline fetcher and a 16-bit prefix byte so that you could use both modes without messing with rep/sep, and constantly have to use php/plp (or have a rigid ABI)
Ditto, 20% of my crashes are due to me exiting a routine/loop/if with the wrong A/X/Y state.

I've gotten better, it was ~60% at the beginning of the year.
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES register sizing schemes (65816 M and X)

Post by psycopathicteen »

Whenever I have a crash, it's always because of some crazy chain reaction.
User avatar
Ramsis
Posts: 341
Joined: Sun Jul 01, 2012 6:44 am
Location: Lion's den :3
Contact:

Re: SNES register sizing schemes (65816 M and X)

Post by Ramsis »

byuu wrote:I always keep 16-bit index registers, and I toggle freely and constantly between 8-bit and 16-bit accumulator.
Ditto. :)
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Re: SNES register sizing schemes (65816 M and X)

Post by Bregalad »

93143 wrote:I find it's useful to be able to quickly stz to an 8-bit PPU register, so I use 8-bit A and 16-bit X/Y. This is also useful for DMA subroutines, since you can pass two 16-bit numbers and an 8-bit number (actually, I think this is probably why I started off with this combination, even though I don't use subroutines any more). And it strikes me that it could be useful to have some indexing capability without losing the ability to load and store both data sizes. There are exceptions, of course - for instance, writing to (especially zeroing) pairs of adjacent PPU registers in a time-critical H-IRQ while deliberately not using X or Y so as to save on stack operations... bit of an edge case, perhaps...
All you're reffereing to is really rare cases, such as "writing to a 8-bit PPU register" or "time-critical H-IRQ". Writing to PPU registers will only be 0.1% of a game's code, and a time-critical H-IRQ won't be needed by 99% of games. So really all you're prooving is that only in some particular cases there's a real advantage to using 8-bit registers. For tech-demoes of course this would be more significant, but nevertheless for game logic I don't see why you wouldn't want to have all registers to be 16-bit.

The only reason to have 8-bit accumulator and 16-bit index is if you're not wanting to change that ever, and that you consider that it is important to have a 8-bit register to write to the hardware reigsters more easily.
93143
Posts: 1371
Joined: Fri Jul 04, 2014 9:31 pm

Re: SNES register sizing schemes (65816 M and X)

Post by 93143 »

I do not pretend that my experience is in any way representative. In fact I explicitly noted that I hadn't written much game logic yet. If I'd had more comprehensive experience, my post would have been a lot shorter.

But I think you may be exaggerating the rarity of the need for an 8-bit register. It's encouraging to me that both byuu and Ramsis seem to handle this essentially the same way I do.
Bregalad wrote:The only reason to have 8-bit accumulator and 16-bit index is if you're not wanting to change that ever
This makes no sense to me.
Post Reply