C/++ for the SNES

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: C/++ for the SNES

Post by Sik »

First I have an 8-bit counter that increments once every frame. Then I take that counter and reverse its bits (i.e. bit 0 becomes 7, bit 1 becomes 6, etc.), this only needs to be done once in the frame since the value is reused for everything. When dealing with assembly you can try abusing carry (rotate left in one register, rotate right in the other, repeat for every bit).

After that, whenever I want to apply momentum, I take the speed value, add that reversed counter value to it, and then shift left 8. The result of that is then added to the coordinate as usual:

Code: Select all

; d0 = Position
; d1 = Speed
; d2 = Counter (zero extended)

    add.w   d2, d1   ; speed += subpixel
    asr.w   #8, d1   ; speed >>= 8
    add.w   d1, d0   ; position += speed
(don't save the modified speed value, of course!)

This same method should be easily doable on the SNES, and I'd assume on the NES as well, even. Here's an example of how well it works. Note that if you want to cheap out, you can get away with less bits, e.g. you could just take four bits from the counter and leave the rest cleared (this gives you steps of 1/16th pixels, which most of the time is more than enough), just make sure that the bits are at the top of the byte and not the bottom.

The two biggest advantages are that it means you need less memory and that everything is measured in pixels (which can help reduce errors). The downside is the sightly added complexity (although for many things you don't even need subpixel momentum anyway, so remember that).

EDIT: added comments.

EDIT 2: coming to think on it, yeah it's pretty much what tepples said, except that instead of being a pseudorandom value it's the most perfect pattern that gets the job done instead (and the addition of 1 comes as a side effect of the calculation, rather than being an explicit branch).
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: C/++ for the SNES

Post by tepples »

This "dithering" of velocity kind of reminds me of Heisenberg's uncertainty principle. Each game object has a precise momentum, but not a precise position.
tomaitheous
Posts: 592
Joined: Thu Aug 28, 2008 1:17 am
Contact:

Re: C/++ for the SNES

Post by tomaitheous »

Sik: What is the advantage to dithering the subpixel part?
__________________________
http://pcedev.wordpress.com
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: C/++ for the SNES

Post by Sik »

It's more even. For example, when the subpixel part is 1/2, the offset is 0,1,0,1,0,1... when it's 1/4 the offset is 0,0,0,1,0,0,0,1,0,0,0,1... you get the idea. Using a (pseudo-)random number doesn't guarantee that the movement will be even like that.

Unless you mean compared to just storing it in the coordinates, in which case well, the advantage is saving memory and keeping everything (non-speed) in pixel units.
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: C/++ for the SNES

Post by psycopathicteen »

Back on subject, asm code does get complicated really fast. I try to keep things simple, but then there's always that extra feature I need to add to my routine, and I end up butchering my elegant looking code for it.
Last edited by psycopathicteen on Tue Nov 25, 2014 4:08 pm, edited 1 time in total.
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: C/++ for the SNES

Post by Sik »

Honestly I think that's more of an issue of the 65816 having so few registers =S
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: C/++ for the SNES

Post by psycopathicteen »

Yes, I was referring to 65816 asm specifically.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: C/++ for the SNES

Post by koitsu »

In my experience, most people who complain about lack of registers on 65xxx platforms come from other architectures where they've already been spoiled (i.e. tainted) via more registers and opcodes which are the equivalent of a bidet. I'm going off historic experiences here, but most of the time it was 68K or x86 people trying to do 65xxx. (Thought as someone who went from 65xxx to x86, I can't tell you how much I hated the fact that mov doesn't set status flags like on the 65xxx. I developed a hatred for test as a result).

But this is why I tell people the 65xxx is a great "starting" processor/platform -- you have limited resources, you learn to develop true KISS and minimal-resource-use mentalities and thought processes.

You then can move to 68K or x86 where all of your secret lusts and desires have been answered *cough cough*.

Buncha whiners. ;-) Like I've said in the past, about the only thing I'd like on the 65816 is native multiplication/division opcodes (and don't refer me to the SNES MMIO registers that rely on a small math IC). Maybe some additional addressing modes, but I'd be fine without that.
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: C/++ for the SNES

Post by rainwarrior »

Nobody tell them about the PowerPC.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: C/++ for the SNES

Post by koitsu »

rainwarrior, I'm sending you a bill for having my LCD cleaned of 7-Up. Thanks a lot. :P
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: C/++ for the SNES

Post by Sik »

Don't forget about processors where the's only an accumulator and nothing else and every operation ends up involving memory instead =P (i.e. literally just a single register, ignoring program counter and such, assuming you can even access those anyway)

The obvious answer to this stuff on 65xx anyway ends up being "use zero page" (and they'll argue that it's actually better because you get 256 bytes, way more than what you get with registers on other CPUs). Well, except for the part that they're also usually used to hold program state as well... but yeah. I think 65816 stores zero page internally anyway.
Kannagi
Posts: 100
Joined: Sun May 11, 2014 8:36 am
Location: France

Re: C/++ for the SNES

Post by Kannagi »

the low register is not really a problem, you have to work with a temporary memory.

Koitsu:
why multiplication / division? most are rather slow on the 68k he made roughly 170 cycles, I think it is better to work with bit shifts
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: C/++ for the SNES

Post by tepples »

Sik wrote:The obvious answer to this stuff on 65xx anyway ends up being "use zero page" (and they'll argue that it's actually better because you get 256 bytes, way more than what you get with registers on other CPUs). Well, except for the part that they're also usually used to hold program state as well
My typical practice on NES has been to use $0000-$000F for those things where I'd use a register on other architectures and $0010-$00FF for program state.
but yeah. I think 65816 stores zero page internally anyway.
Nope. Zero page is just as external on 65816 as it is on 6502. It can just be relocated within $000000-$00FFFF, making it useful as a "frame pointer" for a stack in a C style language (like x86 BP). And some memory controllers may have special fast memory that's mapped to some area of bank $00.
Sik
Posts: 1589
Joined: Thu Aug 12, 2010 3:43 am

Re: C/++ for the SNES

Post by Sik »

Hm, I wonder who was saying around some time ago that the 65816 stored its zero page internally (or is there some other 65xx variant that does?).
tomaitheous
Posts: 592
Joined: Thu Aug 28, 2008 1:17 am
Contact:

Re: C/++ for the SNES

Post by tomaitheous »

I reserve a set of ZP values for pseudo register names (A0-A7, R0-R7, D0-D7); they're 16bit wide. I have equates for accessing the high and low bytes directly (A0.l, A0.h, etc). I have a set of code compact macros to go along with this for non speed essential code, or for prototyping clean looking code (ADD.word #$1234,<D0 or something like ADD.w.byte #$34,<D0 for slightly optimized macros).

But yeah for optimized stuff, you pay the price: convoluted/complex code in trade off for read ability/etc. But I don't mind.

koitsu: I went from x86, to z80, to GBz80, before doing 65x and others. I never really had a problem transitioning. I was surprised by how different the ISA and approach was by comparison at first, but it didn't bother me. X86 actually annoyed me the most. Even though it was my first processor, I couldn't help but feel that it was primitive in design; the register set felt really limited and I didn't even have anything to compare it to (never coded for another processor at the time). Going to the 68k, I couldn't help feel that coders growing up on that processor were just spoiled - hah.
__________________________
http://pcedev.wordpress.com
Post Reply