SNES controller code to work properly.

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
SNES controller code to work properly.
by on (#128831)
Hey been having a bitch of a time trying to understand what's up with code for interacting with the controllers on the SNES. I've read bazz's tutorial (http://wiki.superfamicom.org/snes/show/ ... ller+Input) and the SNES Developer Manual which has some similar sample code.

The issue I am having is that the code seems to react slowly on the real hardware. I've separated out saving the value of the control registers during the vblank and then reacting to the button presses (only changing the bg color). It seems to work okay if I only poll one of the control registers ($4218 or $4219), but when I have more than one button from both control registers it starts to get weird.

The current on is trying to assign a different background color for L trigger, R trigger, R and L (on the d-pad).

I'm assuming it is the timing of the interrupts, but I am also experiencing different results in BSNES/ZSNES/SNES9x/the real hardware (via Power Pak)...
Re: SNES controller code to work properly.
by on (#128833)
Problems I see with this code:

1. EDIT: I misread which register you were reading (re: criticising polling of $4212), sorry about that. I'll leave my other comments though:

The SNES, like many consoles, supports the ability to run some 65816 code when VBlank begins. This is accomplished by setting the NMI vector to some code (which you've done), and then (outside of NMI of course) setting bit #7 of $4200 to 1, which you do. This "ties together" NMI execution when VBlank happens.

VBlank is the period when the electron gun is moving from the bottom of the screen (i.e. an entire screen has just been drawn, down to the last line/pixel, and is now resetting back up to the top to start drawing again).

Within your NMI routine (thus within VBlank) is where you should be doing updates to things like the background scroll registers (if panning around), CGRAM (palette) updates, and (of course) reading the joypad registers (storing the values in some area of RAM (ex. direct page) for use OUTSIDE of NMI).

If you need help understanding what a "proper" flow diagram should be, take a look at the SNES developers manual, specifically Chapter 23. Yes it's many pages, but if you print them out or review them slowly, you'll understand what you should be doing inside of NMI vs. outside of NMI. Although there's some stuff in there that's silly (IMO), like how it recommends re-setting "enable NMI" and some other stuff in your main routine constantly.

Remember: you have more CPU time outside of NMI than you do within NMI, but certain things should be done within NMI (with as minimal processing as possible) to ensure "proper visual updates" every frame. If you start having to do VRAM updates outside of NMI, you need to make sure (through software/logic, and it can be painful) that you're not changing something that you expect to be reflected somewhere above (i.e. before) where the electron gun has already been -- cuz they won't show up until after the next VBlank. Otherwise what you could end up with is a "mid-scanline" type-of effect, where, say, half the screen is blue and half the screen is green (if transitioning from blue->green) for a single frame.

That said: if you want your main (non-NMI) routine to wait for NMI (thus VBlank) to fire: use wai. That's mentioned in the tutorial but I don't see it in your code.

Hope this makes sense. :-)

2. Your NMI joypad reading routine makes absolutely no sense to me. I can't even figure out what the heck you're doing with all these __c and __p variables (EDIT: I guess they stand for "current" and "previous"). All you need to be doing is doing a 16-bit read from $4218 (controller #0), which will get you the "condition" (status) of all the buttons/directions being held at that moment in time (happening 60 times a second, remember -- it's in NMI), and store that result as I said above.

Then in your main loop, if you want to see if L or R (the top L/R buttons, not directional) is pressed, you simply look at the RAM contents (again, 16-bit), do a single bit against the bits you want (ex. bit #$0001 for R, bit #$0002 for L), and bne to some code that handles the situation where the button is pressed.

Alternately, and this is a time-wasting thing to do in NMI (IMO), but you can do an unrolled loop that stores into an individual RAM address the status of each individual button; it's easy using lda/sta/lsr/sta/lsr/sta/lsr/sta... but it's wasteful. The method I mentioned above is easiest, especially if you end up wanting to do something like "do thing X when person is holding up, but do thing X and Y when person is holding up + A".

TL;DR -- I don't understand the purpose behind your ldy/lda/sta/tya/eor/and/sta nonsense. Just do the lda $4212/and #$01/bne loop, read your registers, store them in RAM, do your VRAM/CGRAM/etc. updates, and get outta there.

EDIT: I took a look at the "tutorial" -- now I see what's going on there. Meh, I don't think all that logic is necessarily needed for what you're trying to do, meaning you don't need to do anything if someone releases a button -- all you want to know is if a button is being held and if so do something (ex. increment a colour value if L is being held, otherwise don't increment/do anything).

You should also be doing php/pha/phy at the start, and ply/pla/plp before the rti, because register sizes and contents don't get saved going in/out of NMI. (Add phx/plx in there if you end up using X of course) Part of me wonders if lack of register saving (including P/register sizes) is the cause of some unexpected behaviour.

3. Talking about your CGRAM updates (specifically adjusting $2121 then $2122 to change colour): you should be doing the actual $2121 and $2122 value writes within NMI, because you want to change VRAM (if at all possible) contents during NMI (before the electron gun, thus PPU, has a chance to start reading from things / drawing to the screen).

The way to do this is that in your main loop, when someone presses a button (L, R, etc.), set some flags in some RAM (ex. direct page) locations to indicate "L was pressed". Then in your NMI routine, check if L was pressed (simple lda/beq if you use a single boolean-like variable, e.g. value of 0 or 1, or just go for the lda/bit/bne (or beq to negate the compare of course)), and if so then you change the palette/colour/whatever.

I admit flat out I have not looked at your full main/non-NMI routine to figure out what all you're doing (for example I have no idea what this magical cmp #$56be is about). You're probably trying to do some "special range checking" on your R/G/B values.

4. Speculative: you may be "screwing around" too long in your main (non-NMI) loop and screwing things up. You are literally changing CGRAM while the electron gun draws, which based on timing could have some problems depending on how long things take. Again: this is speculative.

If you want some other example code to look at, you can download my old SNES docs (sndoc230.zip) and within that file is another file called test.zip which contains source code to a small demo/intro-like thing I wrote many years ago. It's commented (albeit badly and I think in one spot there's a mistake), but it's more linear and should help you understand how/when to poll the joypad, when to do graphical updates (although the code just does panning), and that sort of thing. No, it's not code I'm "proud" of per se, but I wrote it 21 years ago (I was 16 at the time), and I think it's an okay starting point.

P.S. -- It makes me happy to see people hacking on and learning the SNES/SFC in this day and age. I still think it's one of the easier 2D consoles to program for (all the "complex annoying stuff" of the NES/FC and 6502 were rectified more or less, so I find it easier to understand/work on. Emulator authors, however, get the shit end of the stick... :/ ).
Re: SNES controller code to work properly.
by on (#128834)
koitsu wrote:
EDIT: I took a look at the "tutorial" -- now I see what's going on there. Meh, I don't think all that logic is necessarily needed for what you're trying to do, meaning you don't need to do anything if someone releases a button -- all you want to know is if a button is being held and if so do something (ex. increment a colour value if L is being held, otherwise don't increment/do anything).

What is wrong with it? It is very annoying if e.g. you are in a menu and have to lightly tap the buttons unless you want the cursor to blast through half the menu, or in games like MMX you usually don't want the users to be able to just hold a button to shoot.
Re: SNES controller code to work properly.
by on (#128836)
Hey guys thanks for the replies!

koitsu wrote:
2. Your NMI joypad reading routine makes absolutely no sense to me.

Hey lol sorry, I made this post after a few days frustration and confusion. Usually I over-comment my code. The way the sequence of checks works after going through it line by line (in other examples), is to get anything that has changed since the previous button press (EOR will make any sequence of 0 --> 1 or 1--> 0 result in a 1). Then it filters out any "presses" with the AND(p was supposed to be previous but I changed it stand for "pressed", I think I left the old comments, my bad).

This is technically overkill for this example, but I'd like to be able to do most of the "common" controller stuff with a more sophisticated example at some point: press, release, hold/charge, tap, and sequences of buttons (hadouken, etc).

koitsu wrote:
You should also be doing php/pha/phy at the start, and ply/pla/plp before the rti, because register sizes and contents don't get saved going in/out of NMI. (Add phx/plx in there if you end up using X of course) Part of me wonders if lack of register saving (including P/register sizes) is the cause of some unexpected behaviour.

forgot about this. I will check if this effects things

koitsu wrote:
I admit flat out I have not looked at your full main/non-NMI routine to figure out what all you're doing (for example I have no idea what this magical cmp #$56be is about). You're probably trying to do some "special range checking" on your R/G/B values.

those were to check if the background already was the color specified by that button, to avoid multiple checks of the same button, I thought that was maybe the case based on what I was experiencing with bsnes.

koitsu wrote:
4. Speculative: you may be "screwing around" too long in your main (non-NMI) loop and screwing things up. You are literally changing CGRAM while the electron gun draws, which based on timing could have some problems depending on how long things take. Again: this is speculative.

possible, I did a working example a while ago where I just made the background change colors in a rainbow fashion. I looked back, I was in fact WAI'ing

koitsu wrote:
If you want some other example code to look at, you can download my old SNES docs (sndoc230.zip)

thanks! just found it.

koitsu wrote:
P.S. -- It makes me happy to see people hacking on and learning the SNES/SFC in this day and age. I still think it's one of the easier 2D consoles to program for (all the "complex annoying stuff" of the NES/FC and 6502 were rectified more or less, so I find it easier to understand/work on. Emulator authors, however, get the shit end of the stick... :/ ).


Yeah! I wish I had a tad more EE/CS knowledge (I went to art school and did some programming-y stuff and then just read some books). Seeing the cool homebrew stuff that is happening keeps me from getting too frustrated. I think the SNES/SFC are about two steps away from a big resurgence in terms of hacking and homebrew, it's just the tools are not all the way there yet.
Re: SNES controller code to work properly.
by on (#128838)
I'm slowly learning SNES programming as well, and have been looking at the same tutorials as you have.
Here are 2 simple programs, if you want to have a look. Written for bass v14 by byuu.
The scrolling one have some dodgy clamping, but it was mostly just to see if I could scroll the screen at all.
https://www.dropbox.com/s/epr3nliq0v7px ... 283%29.rar
https://www.dropbox.com/s/v93oz8dba7he0 ... 282%29.rar
Re: SNES controller code to work properly.
by on (#128850)
DoNotWant wrote:
koitsu wrote:
EDIT: I took a look at the "tutorial" -- now I see what's going on there. Meh, I don't think all that logic is necessarily needed for what you're trying to do, meaning you don't need to do anything if someone releases a button -- all you want to know is if a button is being held and if so do something (ex. increment a colour value if L is being held, otherwise don't increment/do anything).

What is wrong with it? It is very annoying if e.g. you are in a menu and have to lightly tap the buttons unless you want the cursor to blast through half the menu, or in games like MMX you usually don't want the users to be able to just hold a button to shoot.

Using your two examples:

1. "Blasting through half the menu" (ex. by holding Down) is addressed by using delays (usually waiting for VBlank N times) in your main routine. The necessary logic for menuing systems do not need to know "if you previously had the button held down or released it", all they need to know is "is the button being held down right now". In other words: you don't need to know if there was a state change for the Down button between the last frame and the current frame. My test.zip demo is an example of this (using VBlank delays but still having smooth 60fps background panning, while only checking the current state of the button).

2. MMX means Megaman X I assume, and what you're referring to (again assuming) is where Megaman can either shoot his weapon or if you hold down the fire button it charges up over time and then is fired when the button is released. In this case yes, you need to keep some kind of historic data laying around so you can know whether or not the button was simply tapped (standard fire) or is being held down for more than N frames (to start the powering-up of the weapon) and finally released after N frames (to release the powered-up weapon).

Fighting games with combos or timing-sensitive moves are another type which require a kind of "log" of button presses -- I've always wondered how those games (ex. Street Fighter II) actually implemented their joypad routines *and* their logic path (outside of NMI) to handle insane button combinations combined with frame timing. I bet someone somewhere has done a write-up of it and I bet it's scary. :-) But you gotta remember there's also delays that have to be considered (not waiting for VBlank but just overall timing delays), since per-frame analysis is going to be faster than a human being can actually push buttons.

My point here is that what the OP is doing in this particular case doesn't really warrant needing to track previous button states and compare current vs. previous. If he plans on adding something where tapping vs. holding a button is needed, then yeah, keeping a "log" of button presses (possibly just current vs. previous is enough, but then again maybe not, we don't know right now!) is the way to go.
Re: SNES controller code to work properly.
by on (#128852)
Yes, mega man x.

Thanks!
Re: SNES controller code to work properly.
by on (#128853)
koitsu wrote:
1. "Blasting through half the menu" (ex. by holding Down) is addressed by using delays (usually waiting for VBlank N times) in your main routine. The necessary logic for menuing systems do not need to know "if you previously had the button held down or released it", all they need to know is "is the button being held down right now".

Let's say a game's menu samples the controller every 15 frames, triggering an action for each period during which the button was pressed. Sometimes I hold down the button 14 frames and get no actions. Sometimes I hold the button down 16 frames and get two actions. A lot of low-quality falling block games that I've played have logic like this. The way well-tuned games work in practice is to keep one previous frame of data. This way, every time I press down, I get an action. Autorepeat, like you see when you reply to a post and hold down a letter or arrow key, needs two extra historical values: the button that was held and how long it was held. The controller reading code (pads.s) in my NES project template has an example of how to do this on the NES; the Super NES isn't much different.

Quote:
In other words: you don't need to know if there was a state change for the Down button between the last frame and the current frame. My test.zip demo is an example of this (using VBlank delays but still having smooth 60fps background panning, while only checking the current state of the button).

But how easily can you scroll to an individual pixel position? I imagine it'd take a lot of back and forth to get it aligned just so.

Quote:
Fighting games with combos or timing-sensitive moves are another type which require a kind of "log" of button presses -- I've always wondered how those games (ex. Street Fighter II) actually implemented their joypad routines *and* their logic path (outside of NMI) to handle insane button combinations combined with frame timing. I bet someone somewhere has done a write-up of it and I bet it's scary. :-)

Charge attacks like Guile's Sonic Boom are essentially the same logic as autorepeat: store how long the player has pressed back or down. Key combo attacks are a ring buffer of (which key, what frame) pairs, which allows for logic like this:
  • If the last four keys were forward, down, forward, punch, and the oldest of these four was no less recent than 15 frames ago: do a leaping uppercut
  • If the last three keys were down, forward, punch, and the oldest of these three was no less recent than 15 frames ago: throw a fireball
  • If the last three keys were down, back, kick, and the oldest of these three was no less recent than 15 frames ago: do a spinning scissor kick
Re: SNES controller code to work properly.
by on (#128857)
DoNotWant wrote:
I'm slowly learning SNES programming as well...if you want to have a look. Written for bass v14 by byuu.


These look tight, the syntax for bass is a bit arcane to me at the moment though. byuu hangs out in these forums right? Does bass support spc700 code as well? Bass appeals to me for being actively worked on and because he also does bsnes/higan. I also came across that dude lint's stuff (he made that snes version of Kung Fu) and looks like he uses an assembler from WDC (who makes the 65816)...I've been considering a switch from wla, but I think I am going to get my assembly game up first.

koitsu wrote:
My point here is that what the OP is doing in this particular case doesn't really warrant needing to track previous button states and compare current vs. previous. If he plans on adding something where tapping vs. holding a button is needed, then yeah, keeping a "log" of button presses (possibly just current vs. previous is enough, but then again maybe not, we don't know right now!) is the way to go.


I am currently learning the controller stuff to add something in for learning sound coincidentally, but my end goal is to eventually add in sprites and do something like the control test of the SNES Test Program (graphic of a controller) + the control buffer in Chou Aniki. It's not useful now to have the previous states and stuff but will be at some point.
Re: SNES controller code to work properly.
by on (#128859)
Blargg made macro packs to support SPC700 in ca65, both with Sony syntax and with MOS/WDC syntax.
Re: SNES controller code to work properly.
by on (#128860)
tepples wrote:
Quote:
In other words: you don't need to know if there was a state change for the Down button between the last frame and the current frame. My test.zip demo is an example of this (using VBlank delays but still having smooth 60fps background panning, while only checking the current state of the button).

But how easily can you scroll to an individual pixel position? I imagine it'd take a lot of back and forth to get it aligned just so.

With regards to background/screen panning? It's easy -- you can track the X/Y coordinates (probably the "upper left corner") yourself. But if you mean something like: "the BG is already at 45,189 and you want it so when the player taps Up it automatically/smoothly pans to 45,0" or maybe even "...when the player taps Up it pans a little but, but as they hold Up longer the panning speed increases", then yeah that's a bit trickier. That's all done with mathematics at the software level, and while I've only written code like that one in my life (not for the SNES/SFC, but the IIGS, and how to make some graphics move in sine-wave pattern that resembles waves) and I remember having a lot of difficulty wrapping my brain around it (I needed a lot of help from the other guy in our group).

The technical stuff: the BG offset registers (ex. $210d / $210e for BG1) literally accept a raw 10-bit unsigned value of 0-1023 (written via two 8-bit writes) to represent their H/V scroll offset (or a 13-bit signed value of -4096 to 4095 for MODE 7). Interlaced modes and pseudo-512 change this a little bit (I haven't used those though, nor have I done MODE 7). Check out page A-10 in the developers manual for a visual representation of how it works (or A-11 for MODE 7); Nintendo could have done a better job with their diagram though, part of it is confusing as hell.

Screen panning is the one thing that has always impressed the hell out of me on video game consoles -- the premise of a memory-mapped register that just "pans the screen" and when done right its smooth as a baby's butt. The Amiga did a lot of this too (no idea how it works). I guess my interest stems from the fact that the IIGS had absolutely nothing like this, so the concept of smoothly panning around a background (especially with the SNES/SFC and its multiple backgrounds) was mindblowing. There's lots of features on the SNES/SFC that make me drool; that's one of them.
Re: SNES controller code to work properly.
by on (#128864)
there with very good response.
I do not think it is a good idea to make a loop in the vblank
Code:
    v_blank:
    ;---------------------------------------------------------------
    ;wait for joypad to be ready (during VBlank)
    lda $4212
    and #$01
    bne v_blank


If not for my part, I make a simple code in the game loop:

Code:
          lda $4219   ; read joypad 1 High
      AND #$08
      cmp #$08
      bne +
      
         ;code
         
      +:
Re: SNES controller code to work properly.
by on (#128886)
I like how somebody actually said the SNES is easy. Once you get the basics the work such as the interrupts, joypads and oam, it becomes a lot more straightforward. DMA animation became easier when I found out it was actually faster to use a table of DMA transfers than to use an unrolled loop updating 16x16 tile patterns individually.
Re: SNES controller code to work properly.
by on (#128914)
psycopathicteen wrote:
I like how somebody actually said the SNES is easy. Once you get the basics the work such as the interrupts, joypads and oam, it becomes a lot more straightforward. DMA animation became easier when I found out it was actually faster to use a table of DMA transfers than to use an unrolled loop updating 16x16 tile patterns individually.


Yeah I kind of came to the realization that it's not unlike flash/jQuery/openFrameworks which are essentially just a bunch of objects that have to be set up correctly. And as you kind of implied there's not too much crazy timing stuff except stuff like what I am experiencing with the joypads. The problem for me has been the other realization that I don't know assembly that well.
Re: SNES controller code to work properly.
by on (#128935)
Here is a code that does most of the framework necessary for setting up the SNES. I set up a vblank.txt and main.txt, for people to write code without having to deal with all that other timing crap.
Re: SNES controller code to work properly.
by on (#128936)
psycopathicteen wrote:
Here is a code that does most of the framework necessary for setting up the SNES. I set up a vblank.txt and main.txt, for people to write code without having to deal with all that other timing crap.


woah! I was literally just looking at that other code DoNotWANT attached before (The "Sprite" and "Controller" code). What editor do you guys use? I've been on Sublime text and came across syntax highlighting specific to WLA.

I don't think I NEED syntax highlighting, but just curious what you do. It seems like bass mixes some almost "c style" syntax like in the macros.

In regard to my original intention for posting, I've been trying other things, scrolling the background using the controller input. It seems to be working okay, except it will get stuck for a second after a few frames....My code looks pretty similar to what I see in the "Sprite" and "Controller" examples attached before, and I'm doing so little in NMI that I assume my timing is fine, I suspect that I am doing something relatively rudimentary wrong with the stack (I didn't have php/plp initially which might be messing things up).

I've done a few other things with scrolling the background without controller input and experimenting with HSYNC type "wavy effects" and they seemed to be fine so just trying to get over the hump to get these controller stuff working properly.

I'm probably just gonna go back to learning sprite stuff and then try to apply the controller input stuff to that to approach it from another perspective.
Re: SNES controller code to work properly.
by on (#128937)
I just use notepad.
Re: SNES controller code to work properly.
by on (#128938)
psycopathicteen wrote:
I just use notepad.


nice!

the build engine stuff (allowing you to tie a key command to an assembler/compiler command), tabs, and other stuff make Sublime Text pretty worthwhile, but still not as necessary with ASM.
Re: SNES controller code to work properly.
by on (#129019)
So I've still been trying to get this to work.

I switched to try and make the background move via the left and right buttons. It works great on BSNES/higan, however when I tried to upload it to my PowerPak it still hangs up at some even interval. It is a little less than a second. It also makes this buzzing pulse sound if you turn up the volume a little....really weird. The way I found to get rid of the buzzing sound was to get rid of the loop that waits for the controller to be ready, but obviously that makes the controller not work.

I looked at the bass code that other people have attached and structurally my code looks the same...

Is there some other interrupt that might be happening that I am forgetting to deactivate?
Re: SNES controller code to work properly.
by on (#129112)
Your vectors look OK to me.

There is a possible caveat in your VBlank routine that can cause problems later on...

This is how you started your VBlank code:
Code:
    pha

    phx

    phy

    php


This is how you ended your VBlank code:
Code:
    plp

    ply

    plx

    pla

    rti


There are three catches to this code that might be causing a freeze on the PowerPak.

The first is that the accumulator always has sixteen bits in it regardless of whether or not the processor says an 8-bit accumulator or a 16-bit accumulator.

The second is that there is a direct page register (chances are you're not touching it, but if you do touch it in your non-interrupt code and don't account for it in the VBlank or IRQ code, you'll be accessing incorrect memory when using direct page addressing from that point onwards).

The third page is the data bank register (also not accounted for in the VBlank code). If you're touching this register outside of VBlank, then it's likely you're not accessing the actual registers if this ends up being I believe $40-$7F or $C0-FF (I think that's right... could be wrong...).

Plus, the processor status register is actually already saved by default. Thus, the php and plp codes are not nessecary. The rti opcode is there because in addition to returning to where the program left off, it restores the processor status it automatically saved.

This is what I have for my interrupt code at the start to ensure that nothing goes wrong (at least in my eyes)...

Code:
   rep #$30 ;16-bit accumulator and index
   ;Prepare to save all bits of accumulator and index registers...
   phb ;Save data bank...
   phd ;...direct page...
   pha ;...accumulator...
   phx ;...X register...
   phy ;...Y register...
   lda.w #$0000
   tcd ;Set direct page to zero.
   phk ;Set data bank to bank 0.
   plb


And this is what I do at the end to restore everything...

Code:
   rep #$30 ;16-bit accumulator and index
   ply ;Restore all and call it a session.
   plx
   pla
   pld
   plb
   rti


Note that I'm marking the rep and sep codes so that I know what the accumulator and index will become. I actually had problems trying to do it through named variables (I attempted to define some constants and then ORing them together), so I played it straight instead and used the numbers. But I kept the notes there so I knew what I done to the processor through the rep/sep opcodes.
Re: SNES controller code to work properly.
by on (#129129)
Don't you need a php and plp at the beginning and end of the nmi routine?
Re: SNES controller code to work properly.
by on (#129131)
The hardware does PHP for you during an interrupt, and there's a PLP inside the RTI.

(If only it really did <?php ... ?>)
Re: SNES controller code to work properly.
by on (#129132)
To clear up a couple things in the past few posts:

1. On the 65816, before entering an interrupt (IRQ or NMI, doesn't matter), the following things are pushed onto the stack automatically by the CPU in this order: K (active program bank), PC (high), PC (low), and P. When exiting an interrupt (i.e. via RTI), those values are pulled/popped off the stack in reverse order (i.e. normally).

So yes, you do not need PHP/PLP. I suppose this was a "precautionary habit" of mine from my IIGS days where I didn't have books describing the processors' behaviour (I got those near the end of my IIGS stint). However, see point #2 before removing this.

If you need reference material for my statements, refer to the Programming the 65816 (including the 6502, 65C02, and 65802) by Western Design Center PDF (WDC used to have this on their site but it's since gone/missing, but we keep a copy). See the section on Interrupts and System Control Instructions for details.

2. Regarding PHA/PHX/PHY -- "the accumulator always has sixteen bits in it regardless of whether or not the processor says an 8-bit accumulator or a 16-bit accumulator" is a true statement (for those reading it: read it VERY VERY SLOWLY), but has no relevancy with regards to those stack operations. My point written more simply: if you do SEP #$30 / PHA, you're going to push 1 byte onto the stack because the accumulator is 8-bit.

I think we all know that REP #$20 / LDA #$1234 / SEP #$20 / LDA #$FF will result in an accumulator (internally in the CPU) that now contains the value $12FF (but since a=8 you can only manipulate the lower byte). But that fact has no relevancy to concerns over the stack operations unless you're doing something like REP #$20 / LDA #$1234 / PHA / SEP $#20 / PLA (at this point you'd still have a byte left on the stack from the previous 16-bit push).

Thus, the advantage of doing PHA/PHX/PHY/PHP at the start of the NMI routine, followed by PLP/PLY/PLX/PLA at the end -- particularly the use of PHP/PLP here -- is that if you screw around with the accumulator or X/Y sizes (using REP/SEP) in the NMI routine, when exiting NMI and restoring the contents of A/X/Y, you're not going to end up with a stack that eventually overflows or underflows (due to register size differences). Yes, the CPU will effectively do the PHP/PLP for you, but there's no way for you to "run some code after the CPU internally does PLP" to ensure your previous PHA/PHX/PHY statements get popped off the stack with the same sizes they were when you pushed them on at the start of your NMI routine.

The other solution is to do what KungFuKirby did -- explicitly set the accumulator and x/y index sizes to 16-bit using REP #$30 and then do your pushes, and at the end of your routine again do REP #$30 and do your pulls. Which method is better? REP = 3 cycles, PHP = 3 cycles, PLP = 4 cycles. So by using "explicitly use REP" method, you save 1 cycle. Whoop de doo.

3. In KungFuKirby's routine, the reason he does PHB/PLB is because he tinkers with B later (the LDA #$0000 ... PHK / PLB to set B = $00). The reason he does PHD/PLD is because of the LDA #$0000 / TCD which sets D = $0000.

You shouldn't have any concerns about K after exiting NMI because the CPU takes care of that for you. However, there IS a problem if you intermix emulation mode (ex. SEC / XCE) and native mode (to the OP: you can ignore this, this is just me pointing out an esoteric case). Quoting the aforementioned reference material:

Quote:
In native mode, the program bank (K) is pushed onto the stack first, before the program counter and the status register; but in emulation mode it is lost. This means that if a 65816 program is running in emulation mode in a bank other than 0 when an interrupt occurs, there will be no way of knowing where to return to after the interrupt is processed because the origianl bank will have been lost.

This unavoidable but fairly esoteric problem can be dealt with in two ways: the first is simply never to run in emulation mode outside bank 0. The second solution is to store the value of K in a known location before entering emulation mode with a non-zero K register (and is described later in this chapter).


Anyway -- in short, I don't see how any of the stack manipulation code the OP is using would be causing any kind of problem "on the PowerPak" (more specifically, on hardware -- or an emulator for that matter). Analysis of that is a red herring, IMO.

My opinion is that the problem is elsewhere. I have not looked at the latest code version.
Re: SNES controller code to work properly.
by on (#129136)
The push/pops would match, but if your IRQ routine doesn't explicitly set the mode isn't it possible for the CPU to be in either state on entry to the IRQ routine? That seems like a rather large potential source of error, unless your IRQ code is somehow agnostic to the mode.
Re: SNES controller code to work properly.
by on (#129138)
I guess the general moral of the story is that I need to get better with my 65816-specific knowledge/assembly. I actually just picked up a physical copy of the booked linked before, was trying to get it printed at fedex office but it seemed pretty unreasonable price wise. The one I found had a coffee stain or something and was only $40, the other ones I've seen are $150+. That's just me, I prefer physical books/being able to annotate them/flip pages rapidly. The native PDF viewer in windows 8 also sucks major balls.

In trying to suss out the nature of the issue, I removed different sections of the vblank code, and tried it with a bunch of permutations of with/without php/plp pha/pla to see if they made a difference. This was only to get rid of the weird periodic pausing for like .2/half a second. I don't remember the results of each (It was around 2/3AM the other day), but getting rid of the loop that waits for $4212 seemed to get rid of it, but obviously this causes the controllers to not work.

Are there any other interrupts that I might not be considering? I was doing some stuff here with IRQ to get waving effects:

https://vimeo.com/85569649

I honestly am not sure exactly what I was doing, I know some of it I got from looking at the SNES dev manual and pretty much explicitly following what was there. I might look into if I need to explicitly disable the IRQ to make sure that isn't somehow happening.
Re: SNES controller code to work properly.
by on (#129139)
tepples wrote:
The hardware does PHP for you during an interrupt, and there's a PLP inside the RTI.

(If only it really did <?php ... ?>)


ha the code would be a mess, you'd $ in front of variables and $ in front of hex numbers.
Re: SNES controller code to work properly.
by on (#129144)
rainwarrior wrote:
The push/pops would match, but if your IRQ routine doesn't explicitly set the mode isn't it possible for the CPU to be in either state on entry to the IRQ routine? That seems like a rather large potential source of error, unless your IRQ code is somehow agnostic to the mode.

You're correct -- the state of a/x/y sizes is unknown (AFAIK it will be whatever it was at the moment NMI was induced), so setting it explicitly in NMI using REP/SEP is wise.