SNES controller code to work properly.

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
benjaminsantiago
Posts: 84
Joined: Mon Jan 20, 2014 9:40 pm
Location: Astoria, NY
Contact:

Re: SNES controller code to work properly.

Post by benjaminsantiago »

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.
Last edited by benjaminsantiago on Mon May 19, 2014 12:13 pm, edited 1 time in total.
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES controller code to work properly.

Post by psycopathicteen »

I just use notepad.
User avatar
benjaminsantiago
Posts: 84
Joined: Mon Jan 20, 2014 9:40 pm
Location: Astoria, NY
Contact:

Re: SNES controller code to work properly.

Post by benjaminsantiago »

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.
User avatar
benjaminsantiago
Posts: 84
Joined: Mon Jan 20, 2014 9:40 pm
Location: Astoria, NY
Contact:

Re: SNES controller code to work properly.

Post by benjaminsantiago »

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?
Attachments
joypad__full_img_4bpp.zip
(157.49 KiB) Downloaded 67 times
KungFuFurby
Posts: 264
Joined: Wed Jul 09, 2008 8:46 pm

Re: SNES controller code to work properly.

Post by KungFuFurby »

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: Select all

    pha 

    phx

    phy

    php
This is how you ended your VBlank code:

Code: Select all

    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: Select all

	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: Select all

	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.
psycopathicteen
Posts: 3001
Joined: Wed May 19, 2010 6:12 pm

Re: SNES controller code to work properly.

Post by psycopathicteen »

Don't you need a php and plp at the beginning and end of the nmi routine?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: SNES controller code to work properly.

Post by tepples »

The hardware does PHP for you during an interrupt, and there's a PLP inside the RTI.

(If only it really did <?php ... ?>)
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: SNES controller code to work properly.

Post by koitsu »

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:
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.
User avatar
rainwarrior
Posts: 8062
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: SNES controller code to work properly.

Post by rainwarrior »

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.
User avatar
benjaminsantiago
Posts: 84
Joined: Mon Jan 20, 2014 9:40 pm
Location: Astoria, NY
Contact:

Re: SNES controller code to work properly.

Post by benjaminsantiago »

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.
User avatar
benjaminsantiago
Posts: 84
Joined: Mon Jan 20, 2014 9:40 pm
Location: Astoria, NY
Contact:

Re: SNES controller code to work properly.

Post by benjaminsantiago »

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.
User avatar
koitsu
Posts: 4203
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: SNES controller code to work properly.

Post by koitsu »

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.
Post Reply