SNES Programing Help 2

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.
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: SNES Programing Help 2

Post by Khaz »

Heh. I'm quite content doing literally everything in Hex. It's only taken a couple months or so for it to become second nature to me, and that way there's never any misunderstanding about what my code is doing. In most cases it's even easier than thinking in decimal: A standard tile is $10 or 16, so say 17 of them would be $170 or (let me get a calculator).

Speaking of you can always use the windows calculator in "Programmer" mode to do conversions and math in hex/binary that you can't do in your head (If you use Windows).
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: SNES Programing Help 2

Post by Drew Sebastino »

You know, I've been a bit busy with school so I haven't been able to work on anything, but I should have some free time and I wanted to implement the velocity thing for the bullets, but I just realized something. I was originally going to use a word for velocity and a word for the position, and I was going to only take the highest byte from the velocity and add that to the position, as this would allow for "sub pixel precision", but I later realized that I wouldn't be able to have "negative" velocity, because I couldn't get a 16 space to wrap around using an 8 bit number. Do you have any good ideas as to have both "sub pixel velocity" and "negative velocity"?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: SNES Programing Help 2

Post by tepples »

If you ignore the low byte and add only the high byte to the velocity, then you can't have motion slower than 1 pixel per frame. There is a workaround involving adding a bit-reversed version of the current frame number to the low byte of the velocity and then adding the carry from there and the high byte of the velocity to the displacement.

I don't see how a two's complement negative velocity would introduce problems. What problems have you seen?
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES Programing Help 2

Post by psycopathicteen »

The way I've been doing subpixel negative values is by doing this:

Code: Select all

lda {x_velocity}     //if greater than $8000, N flag is set
bpl +                        //branch if plus
dec {x_position_hi}     //decrease high-word of x position if velocity is negative
+;
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: SNES Programing Help 2

Post by Khaz »

In my setup velocity is two bytes where the hi byte represents actual pixels/frame, and position is 3 bytes where the middle represents actual pixels. I branch based on whether velocity is positive or negative, add the sub-velocity to the sub-position in 16-bit mode, then bcc or bcs appropriately to increment or decrement the hi-byte of position.

I'm sure there's some better way...
User avatar
Myask
Posts: 965
Joined: Sat Jul 12, 2014 3:04 pm

Re: SNES Programing Help 2

Post by Myask »

That's what the carry/borrow part of ADC/SBC is for, to let you easily carry/borrow lower portions of a multi-byte(/multi-word, for SNES) addition/subtraction.
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: SNES Programing Help 2

Post by Khaz »

Myask wrote:That's what the carry/borrow part of ADC/SBC is for, to let you easily carry/borrow lower portions of a multi-byte(/multi-word, for SNES) addition/subtraction.
I'm not sure if this was being addressed to my comment but if so: Do you mean to say I'm doing things as intended or are you proposing a faster way? I've set it up like this:

Code: Select all

	lda.b objYVelo	;16-bit A initially
	beq _doneObjYVelo
	bpl _goinDown
	
	clc					;goin' Up
	adc.b objYPosnSub
	sta.b objYPosnSub	;Velocity was NEGATIVE.  
	bcs _doneObjYVelo	;So if carry is CLEAR, we need to DECREMENT high byte

	sep #$20		;8-bit A
	dec.b objYPosnHi
	rep #$20		;16-bit A
	bra _doneObjYVelo

_goinDown:
	clc
	adc.b objYPosnSub
	sta.b objYPosnSub	;Velocity was POSITIVE.  
	bcc _doneObjYVelo	;If carry is SET, we need to INCREMENT high byte

	sep #$20		;8-bit A
	inc.b objYPosnHi
	rep #$20		;16-bit A

_doneObjYVelo:
Which, aside from being extra-cautious about overflows on the high byte, is as efficient as I can think of a way to do it. I know you can use an ADC #$00 on the Hi byte to stuff the carry in there without a branch, at least on the second half, but that seems like it costs more cycles. Am I missing something or have I got it right?

(P.S. I instinctively put the "beq _doneObjYVelo" at the start to eliminate all the processing when your velocity is zero. I do that a lot but I suddenly think that's a mistake - since it will speed up processing some of the time but ultimately make the worst-case scenario take slightly longer. I should refrain from doing that, right?)
User avatar
Myask
Posts: 965
Joined: Sat Jul 12, 2014 3:04 pm

Re: SNES Programming Help 2

Post by Myask »

It was, but...
I know you can use an ADC #$00 on the Hi byte to stuff the carry in there without a branch, at least on the second half, but that seems like it costs more cycles.

Code: Select all

LDA imm: 2b 2c
ADC/SBC mem: 2b, 3c
STA mem: 2b, 3c
total: 8b, 10c
vs 
BC*: 2b, 2c (3c not, but ditches the SEP/REP too for net -3c)
INC/DEC mem: 2b, 5c
total: 5b, 8c
You're right. Silly of me to think that the obvious method would be cheaper. (if indexed/not direct page, the gap just widens, as the ADC method has two instructions gaining cycles rather than one.)

Small optimization: put the CLC before the LDA.b objYVelo, rather than in both branches. LDA doesn't affect carry.
I instinctively put the "beq _doneObjYVelo" at the start [...] I should refrain from doing that, right?
Probably unnecessary/unuseful. It depends on what your 'worst-case' where you're actually needing time-saved looks like. Untaken branch takes 2 cycles each time, after all, so when is 2*moving_objects < (processing_time -3) * unmoving_objects?

...say, why AREN'T you using indexed modes here? Aren't you iterating over the list of objects?
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES Programing Help 2

Post by psycopathicteen »

To avoid repetitive index register juggling.
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: SNES Programing Help 2

Post by Khaz »

Yeah, I'm using direct page to iterate through my list of objects, hence all the ".b" instructions.

Thanks for the input!
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: SNES Programing Help 2

Post by Drew Sebastino »

Sorry to steer this conversation off topic a little, but there's one thing I've been doing that I'm sure there's a better way to do. I have it to when whenever I set a certain bit to the metasprite routine, it creates a horizontally flipped version of the metasprite, but I wasn't sure how to efficiently make one routine be able to do both, so I literally did this...

Code: Select all

  lda MetaspriteDirection
  bne backwards_metasprite_loop
Which means I completely copied the code again except I subtracted the sprites position from the objects instead of adding and I eor'd at one point to change the flip bit. I know there's a better way to do this, and at some point, I want to also have sprites flipped vertically, and that means I'd have to copy the routine 4 times... I know I could look to see if the bit was set to change direction every time I do something that related to the object being flipped, but this would use some more processing time so don't know...
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: SNES Programing Help 2

Post by Khaz »

Espozo wrote:Sorry to steer this conversation off topic a little...
Helping you is literally the topic. :wink:
Espozo wrote:I know there's a better way to do this, and at some point, I want to also have sprites flipped vertically, and that means I'd have to copy the routine 4 times... I know I could look to see if the bit was set to change direction every time I do something that related to the object being flipped, but this would use some more processing time so don't know...
I personally found psycopathicteen's reply to you back in December very helpful for that. It needs a bit of adjustment to be functional (position is off-by-one on flipping and I have no clue what his plan was with the x-position and size bits for the second OAM table), but I found the approach downright elegant.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: SNES Programing Help 2

Post by Drew Sebastino »

Khaz wrote:
Espozo wrote:Sorry to steer this conversation off topic a little...
Helping you is literally the topic. :wink:
Yeah... :oops: I just figured I was moving on from the velocity thing for now.
Khaz wrote:
Espozo wrote:I know there's a better way to do this, and at some point, I want to also have sprites flipped vertically, and that means I'd have to copy the routine 4 times... I know I could look to see if the bit was set to change direction every time I do something that related to the object being flipped, but this would use some more processing time so don't know...
I personally found psycopathicteen's reply to you back in December very helpful for that. It needs a bit of adjustment to be functional (position is off-by-one on flipping and I have no clue what his plan was with the x-position and size bits for the second OAM table), but I found the approach downright elegant.
Oh, thanks for finding that again. :) I didn't have the slightest clue as to what was going on originally, but now that I've learned a bit since then, I kind of understand it now. Maybe psychopathicteen can explain it some more here.
User avatar
Memblers
Site Admin
Posts: 3901
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: SNES Programing Help 2

Post by Memblers »

Try to avoid copying code. That's when it's best to use a macro, with parameters for the parts that vary. Same result, but it's always good to edit the code in one place instead of 4.

If you wanted to avoid subtraction, instead of SBC #8 you could do ADC #$F8 (or $FFF8) for the same result. Though I know that doesn't help much, that just moves the branch elsewhere, figured I'd throw that in as well.
User avatar
Drew Sebastino
Formerly Espozo
Posts: 3496
Joined: Mon Sep 15, 2014 4:35 pm
Location: Richmond, Virginia

Re: SNES Programing Help 2

Post by Drew Sebastino »

Memblers wrote:If you wanted to avoid subtraction, instead of SBC #8 you could do ADC #$F8 (or $FFF8) for the same result. Though I know that doesn't help much, that just moves the branch elsewhere, figured I'd throw that in as well.
I know. (Even if I did just learn recently...) The thing is that the number that is being sbc'd/adc'd is the same, so I cannot really change it. Hey, maybe at the beginning of the code, I could check if the object is backwards, and if it is, I then add #$F000 to the position of the sprite position that gets added to the metasprite position... To make sure it to where it loads either #$0000 or #$F000, I'll make it look at a register that will only ever have those 2 values. (This is the result of if the object is backwards or forwards that gets filled at the beginning of the code.)

By the way, what is the opcode "bit" do?
Post Reply