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 »

Espozo wrote:
UnDisbeliever wrote:I think your problem is that your trying to access the Metasprite* variables (by .importzp) and the objects as a 1 byte address at the same time. When you set the DP register all 1 byte addresses will be added to DP to form the effective address.
What? :| What do you mean by "When you set the DP register all 1 byte addresses will be added to DP to form the effective address."? What are the "1 byte addresses?" How do I fix this particular problem?
UnDisbeliever wrote:Secondly, the value of ObjectTableis $0620 according to map.txt. Masking it to a 1 byte addresses will not work as you anticipate. What I think you are after is adc <YPosition after setting DP to #ObjectTable.
Again, what?
What he's getting at here is that it seems like you have other instructions that are also using direct page at the same time, so your D register is only set correctly for some instructions and the others are accessing the wrong address.

Regarding the second point specifically, it's referring to where you wrote earlier "adc <ObjectTable+YPosition". The problem with this (I THINK) is that the < is being applied immediately to ObjectTable and cutting out the hi byte, then adding YPosition. Either way, the better solution is definitely to put ObjectTable + ObjectOffset in D and then just "adc <YPosition", just like you said. A possibly even more betterer solution would be to store the absolute address of each object slot instead of just an offset from the start of the table. That way you don't have to add anything, just "lda ObjectSlotAddress", "tcd".

So, yeah, I'm guessing the first sentence there is probably your problem. Look through your code and make sure you don't have instructions using direct page addressing (ie/ a one-byte address for an operand) when they shouldn't be (I believe this is what listing files are good for). Make sure that the D register is set correctly for the instructions you DO want using direct page addressing (I like trace logs for that personally).
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: SNES Programing Help 2

Post by koitsu »

You can confirm some of Khaz's suspicions by looking at the generated assembly listing by ca65 (see relevant .lst file). I really am starting to sound like a broken record.

Footnote: I don't tend to recommend using the < shorthand operators in ca65, I tend to resort to using .LOBYTE(thing) or .LOWORD(thing) (there is also HIBYTE/HIWORD). And I say that after multiple decades of using < and > with older assemblers. Reference material: http://cc65.github.io/doc/ca65.html#s10
UnDisbeliever
Posts: 77
Joined: Mon Mar 02, 2015 1:11 am
Location: Australia (PAL)
Contact:

Re: SNES Programing Help 2

Post by UnDisbeliever »

Espozo wrote: What? :| What do you mean by "When you set the DP register all 1 byte addresses will be added to DP to form the effective address."? What are the "1 byte addresses?" How do I fix this particular problem?
Sorry about that, I was rushed for time.

Please read page 298 (Direct Page Addressing) of the 65c816 Programming Manual (PDF) for a diagram explaining what happens. Any load/store/cmp instruction that uses a single byte address is direct page.

You can check that by looking at the .lst files and count the number of bytes they are using.

Code: Select all

000000r 1               .proc start_metasprite
000000r 1  0B             phd
000001r 1  C2 30          rep #$30    ; A=16, X/Y=16
000003r 1  A4 rr          ldy SpriteCount
000005r 1  A6 rr          ldx MetaspriteTableOffset
000007r 1               
000007r 1  A9 rr rr       lda #ObjectTable
00000Ar 1  18             clc
00000Br 1  65 rr          adc ObjectOffset
00000Dr 1  5B             tcd
00000Er 1               
00000Er 1  64 rr          stz HFlipMask
000010r 1  A5 rr          lda MetaspriteDirection
000012r 1  89 01 00       bit #$0001
000015r 1  F0 05          beq metasprite_loop
000017r 1  A9 FF FF       lda #$FFFF
00001Ar 1  85 rr          sta HFlipMask
00001Cr 1               

You can see that the SpriteCount, MetaspriteTableOffset, ObjectOffset, HFlipMask, MetaspriteDirection (and others) are using direct page addressing (1 byte addresses). Because you have set the DP register to something other than $0000, that value will be added to the address to form the effective one. This is probably causing some value in your object dataset to be overridden. When you read the same code through a trace logger you can see what I'm trying to explain.

Code: Select all

$00/80C0 0B          PHD                     A:0000 X:8703 Y:0000 D:0000 DB:00 S:1FF9 P:envmxdiZC HC:0538 VC:231 FC:06 I:00
$00/80C1 C2 30       REP #$30                A:0000 X:8703 Y:0000 D:0000 DB:00 S:1FF7 P:envmxdiZC HC:0624 VC:231 FC:06 I:00
$00/80C3 A4 22       LDY $22    [$00:0022]   A:0000 X:8703 Y:0000 D:0000 DB:00 S:1FF7 P:envmxdiZC HC:0662 VC:231 FC:06 I:00
$00/80C5 A6 14       LDX $14    [$00:0014]   A:0000 X:8703 Y:0000 D:0000 DB:00 S:1FF7 P:envmxdiZC HC:0710 VC:231 FC:06 I:00
$00/80C7 A9 20 06    LDA #$0620              A:0000 X:8703 Y:0000 D:0000 DB:00 S:1FF7 P:eNvmxdizC HC:0758 VC:231 FC:06 I:00
$00/80CA 18          CLC                     A:0620 X:8703 Y:0000 D:0000 DB:00 S:1FF7 P:envmxdizC HC:0798 VC:231 FC:06 I:00
$00/80CB 65 26       ADC $26    [$00:0026]   A:0620 X:8703 Y:0000 D:0000 DB:00 S:1FF7 P:envmxdizc HC:0828 VC:231 FC:06 I:00
$00/80CD 5B          TCD                     A:0620 X:8703 Y:0000 D:0000 DB:00 S:1FF7 P:envmxdizc HC:0876 VC:231 FC:06 I:00
$00/80CE 64 1E       STZ $1E    [$00:063E]   A:0620 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdizc HC:0906 VC:231 FC:06 I:00
$00/80D0 A5 16       LDA $16    [$00:0636]   A:0620 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdizc HC:0960 VC:231 FC:06 I:00
$00/80D2 89 01 00    BIT #$0001              A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:1014 VC:231 FC:06 I:00
$00/80D5 F0 05       BEQ $05    [$80DC]      A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:1054 VC:231 FC:06 I:00
$00/80DC C0 00 02    CPY #$0200              A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:1092 VC:231 FC:06 I:00
$00/80DF F0 67       BEQ $67    [$8148]      A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:eNvmxdizc HC:1132 VC:231 FC:06 I:00
$00/80E1 29 FF 00    AND #$00FF              A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:eNvmxdizc HC:1164 VC:231 FC:06 I:00
$00/80E4 99 01 02    STA $0201,y[$00:0201]   A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:1204 VC:231 FC:06 I:00
$00/80E7 A5 1C       LDA $1C    [$00:063C]   A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:1266 VC:231 FC:06 I:00
$00/80E9 F0 5D       BEQ $5D    [$8148]      A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:1320 VC:231 FC:06 I:00
$00/8148 84 22       STY $22    [$00:0642]   A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:1358 VC:231 FC:06 I:00
$00/814A 2B          PLD                     A:0000 X:8703 Y:0000 D:0620 DB:00 S:1FF7 P:envmxdiZc HC:0048 VC:232 FC:06 I:00
$00/814B 60          RTS                     A:0000 X:8703 Y:0000 D:0000 DB:00 S:1FF9 P:envmxdiZc HC:0100 VC:232 FC:06 I:00

The effective address being read (the one in square braces) is the memory address being read for that instruction. In this case, your lda MetaspriteDirection (line $00/80D0) is actually reading address $00:0636 instead of the correct address of $00:0016 allocated by ca65. Thus its reading the wrong value and branching incorrectly.
Espozo wrote: Edit: I tried what I just suggested, and it still doesn't work. :?
MetaspriteDemoKoitsu.rar
I guess it still doesn't work because of problems #1 and #2 you said?
Yeah. You solved problem 2 (wrong address), now you need to solve problem 1 (using DP addressing for non-object variables).

You can fix this by either moving the variables Empty, MetaspriteTableOffset, MetaspriteDirection, MetaspritePalette, MetaspriteCharacterOffset, MetaspriteCount, HFlipMask, VFlipMask, SpriteCount, NewObjectRequest, ObjectOffset out of .zeropage and into .BSS and replacing their .importzp/.exportzp with .import/.export.

Or you can force absolute addressing on these variables with the a: modifier.

Code: Select all

  lda a:Empty,x               ; 1st byte = sprite X position (value 0-255)
  eor a:HFlipMask
  clc
  adc <XPosition
  cmp #256
  bcc sprite_x_not_out_of_bounds
  cmp #65504
Personally I prefer the first, but you may need to do the second sometime in the future (I have with the NPC vs player interaction code).

I also recommend you place the object variables in a struct (like I mentioned in my previous post), it makes the code a lot easier to manage if you have separate code for heroes and objects.

(sorry about not making this clearer).

Mod edit (koitsu): I updated the URL for the 65816 manual; WDC moved this somewhat recently.
Last edited by UnDisbeliever on Tue Mar 17, 2015 12:09 am, edited 1 time in total.
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 »

And if you need to use indirection while you have direct page set elsewhere, you can push the address and use the (d,s),y addressing mode.
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 »

Yes! a: Worked! You have no idea how happy you all have made me! :mrgreen:
UnDisbeliever
Posts: 77
Joined: Mon Mar 02, 2015 1:11 am
Location: Australia (PAL)
Contact:

Re: SNES Programing Help 2

Post by UnDisbeliever »

Espozo wrote:Yes! a: Worked! You have no idea how happy you all have made me! :mrgreen:
No problem, we need more SNES developers in the world. :D
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 »

UnDisbeliever wrote:
Espozo wrote:Yes! a: Worked! You have no idea how happy you all have made me! :mrgreen:
No problem, we need more SNES developers in the world. :D
Truer words have not been spoken.
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 »

Well, I've ran into another (thankfully much smaller ) dilemma. I have an "attributes" byte in every object slot that is exactly like bytes 3 and 4 in oam, and I was having it to where every time I press left, I have bit %0100000000000000 get loaded with a 1, and whenever I press right, I get bit %0100000000000000 loaded with a 1. I don't want this to interfere with any of the other bits. Left is easy in that I can do

Code: Select all

  lda ObjectTable+Attributes,y
  ora #$4000
  sta ObjectTable+Attributes,y
But I can't for right, because I want the value to be 0, and ora only puts in 1s. Eor wouldn't work either, because it always flips the value, so it isn't really like the opposite of ora. I currently just do

Code: Select all

  lda ObjectTable+Attributes,y
  ora #$4000
  eor #$4000
  sta ObjectTable+Attributes,y
But I was wondering if maybe there was a instruction that was like ora for 0s.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: SNES Programing Help 2

Post by tokumaru »

Espozo wrote:But I was wondering if maybe there was a instruction that was like ora for 0s.
Just AND the opposite of the mask:

Code: Select all

ora #%0100000000000000 ;sets bit 14
and #%1011111111111111 ;clears bit 14
EDIT: forgot the #s!
Last edited by tokumaru on Wed Mar 18, 2015 1:13 pm, edited 1 time in total.
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 »

It's sad that that didn't occur to me...
KungFuFurby
Posts: 264
Joined: Wed Jul 09, 2008 8:46 pm

Re: SNES Programing Help 2

Post by KungFuFurby »

Espozo wrote:
UnDisbeliever wrote:
Espozo wrote:Yes! a: Worked! You have no idea how happy you all have made me! :mrgreen:
No problem, we need more SNES developers in the world. :D
Truer words have not been spoken.
Seconded. My own fandom of developing a SNES game is taking years to accomplish (My fandom is at least 10 years old and counting!), but I at least have one key component working in my favor: the music. I've been perfecting this, and I fully intend to bring out full length music once I make a working sound driver that can swap out data as needed (as well as implementing stopgaps in case swapping takes longer than expected).
User avatar
Khaz
Posts: 314
Joined: Thu Dec 25, 2014 10:26 pm
Location: Canada

Re: SNES Programing Help 2

Post by Khaz »

KungFuFurby wrote:Seconded. My own fandom of developing a SNES game is taking years to accomplish (My fandom is at least 10 years old and counting!), but I at least have one key component working in my favor: the music. I've been perfecting this, and I fully intend to bring out full length music once I make a working sound driver that can swap out data as needed (as well as implementing stopgaps in case swapping takes longer than expected).
I still have yet to make the SNES make a noise. I was thinking of just holding out until that SNES Tracker I keep hearing about is published/functional, but now I'm just trying to learn to do everything myself in raw assembly / bytes. I understand the BRR format no problem. I get the general idea of what I have to do - write code to operate the SPC700 and then write code to transfer that code over to it. It's just moving at a snail's pace due to the I would say EXTREMELY lacking documentation in this area. I learn roughly a thousand times faster when I have even just one functional example to look at and such a thing does not seem to exist for SNES music, at least not in the actual assembly language. You know, without decompiling a commercial ROM...

I honestly can't even find one single document that has all the information I need in it. I mean, it might be out there, but everything I've found is painfully incomplete and has to be read two or three times just to understand the less than half of the story it's telling you.
KungFuFurby
Posts: 264
Joined: Wed Jul 09, 2008 8:46 pm

Re: SNES Programing Help 2

Post by KungFuFurby »

http://problemkaputt.de/fullsnes.htm

I use this one. Works well enough for my intentions.

Any details in particular you were wondering about?

I have three SPC700 assembly (well... two of them use non-native syntax) sound driver examples.

SNESGSS (caution, link may not last much longer, given that Google Code is in the process of shutting down to my knowledge... I think...) is a working sound driver. Syntax used is not native, though, and it compiles with bass (haven't tested it myself because I never compiled the program).

mukunda's SNESMod also counts for an example. This one uses TASM as an assembler, and uses native SPC700 syntax.

There's a third sound driver which again does not use native syntax. It also uses its own assembler. The sound driver is made by Paul Lay.
Home page for where the sound driver is used
The source is found in Cute Angel(a).
User avatar
Holt
Posts: 4
Joined: Sat Mar 07, 2015 6:40 pm

Re: SNES Programing Help 2

Post by Holt »

KungFuFurby wrote:http://problemkaputt.de/fullsnes.htm

I use this one. Works well enough for my intentions.

Any details in particular you were wondering about?

I have three SPC700 assembly (well... two of them use non-native syntax) sound driver examples.

SNESGSS (caution, link may not last much longer, given that Google Code is in the process of shutting down to my knowledge... I think...) is a working sound driver. Syntax used is not native, though, and it compiles with bass (haven't tested it myself because I never compiled the program).

mukunda's SNESMod also counts for an example. This one uses TASM as an assembler, and uses native SPC700 syntax.

There's a third sound driver which again does not use native syntax. It also uses its own assembler. The sound driver is made by Paul Lay.
Home page for where the sound driver is used
The source is found in Cute Angel(a).
Thanks for this! I really appreciate it! I've sent you a PM re: a question on this. No need to reply, but just letting you know. Thanks.
User avatar
Ramsis
Posts: 341
Joined: Sun Jul 01, 2012 6:44 am
Location: Lion's den :3
Contact:

Re: SNES Programing Help 2

Post by Ramsis »

Hey, Khaz!
Khaz wrote:I learn roughly a thousand times faster when I have even just one functional example to look at and such a thing does not seem to exist for SNES music, at least not in the actual assembly language. You know, without decompiling a commercial ROM...
For a working homebrew SPC700 example, have a look at e.g. d4s's N-Warp Daisakusen sourcecode.

The results of an (attempted/incomplete?) disassembly of a commercial ROM's sound engine can be found at lytron's Bounty Sword SPC Disassembly.

Hope that helps! :D

Ramsis
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)
Post Reply