SNES Splatoon (How do I shot HiROM?)
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
Re: SNES Splatoon (How do I shot HiROM?)
Let's put it this way: yes, you're going to try to do the best you can to make sure your code doesn't take too long and create lag frames. But in case it does happen (and it's likely there will be some edge case where it does), which would you rather happen?
a) The game just lags.
b) The game behaves erratically, writing unpredictable values to unpredictable locations, possibly crashing and burning, drawing garbage to the screen, making branches misfire, sending garbage to the SPC, causing all sorts of unreproducable, nigh-undebuggable problems.
Because b) is what you're risking if you don't preserve everything in your interrupt handlers. It is not worth it to leave those out just to save a few cycles in your handlers, just because you're pretty sure you won't lag.
a) The game just lags.
b) The game behaves erratically, writing unpredictable values to unpredictable locations, possibly crashing and burning, drawing garbage to the screen, making branches misfire, sending garbage to the SPC, causing all sorts of unreproducable, nigh-undebuggable problems.
Because b) is what you're risking if you don't preserve everything in your interrupt handlers. It is not worth it to leave those out just to save a few cycles in your handlers, just because you're pretty sure you won't lag.
Re: SNES Splatoon (How do I shot HiROM?)
When an interrupt occurs, it can happen at any time, including in the middle of an instruction. The interrupt handler won't kick in until the actively-executing instruction completes. In other words, even if NMI occurs in the middle of the lda #$1234 instruction in my example, transfer to the NMI vector won't happen until after the lda #$1234 completes. This is well documented throughout all decent 65xxx documentation (for the 65816, see Western Design Center's documentation). Use of wai can be used to wait for an interrupt (NMI in this case) to occur and finish, but you already know that.Kannagi wrote:Yes I understand, the VBlank, it can occur at any time?
Normally it does not come at the end of the final line ?
There is an example or VBlank comes before?
None of the above has any relevance to what's being discussed.
What's being discussed is the fact that register contents are not automatically saved/restored when entering/exiting an interrupt. It's your responsibility to save them. Otherwise when the interrupt exits (rti) and control is returned to the "main" program, register contents are whatever they were prior to rti being executed. This is also documented clearly in 65xxx documentation, but I'll even quote WDC for you (page 277) -- I've made cyan the relevant parts:
In other words: back up your registers (including P, D, B, or anything else you tweak in your NMI routine), and restore them (in the correct order) before doing rti. The end.Interrupt-Handling Code
To correctly handle 65x interrupts, you should generally, at the outset, save all registers and, on the 6502 and in emulation mode, clear the decimal flag (to provide a consistent binary approach to arithmetic in the interrupt handler). Returning from the interrupt restores the status register, including the previous state of the decimal flag.
During interrupt handling, once the previous environment has been saved and the new one is solid, interrupts may be enabled.
At the end of handling interrupts, restore the registers in the correct order. RTI will pull the program counter and status register from the stack, finishing the return to the previous environment, except that in 65802/65816 native mode it also pulls the program bank register from the stack. This means you must restore the mode in which the interrupt occurred (native or emulation) before executing an RTI.
- rainwarrior
- Posts: 8062
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: SNES Splatoon (How do I shot HiROM?)
NMI is generated on any rising edge of the signal, so anything that causes it to go from low to high can trigger a spurious NMI.psycopathicteen wrote:When does it NMI besides vblank?
On the NES this can happen if you flip the mask bit via the control register during vblank. I believe SNES has an equivalent thing? Though, this is actually a case where you know exactly where the NMI is going to fire in your code, since it's directly triggered by a register write.
I don't think koitsu was intentionally talking about this, though. I think he just meant to express that it's hard to predict where vblank is going to begin relative to your code, so you should never rely on this without good reason to do so.
Re: SNES Splatoon (How do I shot HiROM?)
Once again, P (processor status) is saved automatically when an interrupt fires, and restored automatically by the rti opcode. In other words, there's normally no need to do php / plp at the beginning and end of your IRQ/NMI handler.koitsu wrote:In other words: back up your registers (including P, D, B, or anything else you tweak in your NMI routine), and restore them (in the correct order) before doing rti. The end.
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)
Re: SNES Splatoon (How do I shot HiROM?)
And this doesn't just apply to registers -- you also have to watch your variables.Nicole wrote:b) The game behaves erratically, writing unpredictable values to unpredictable locations, possibly crashing and burning, drawing garbage to the screen, making branches misfire, sending garbage to the SPC, causing all sorts of unreproducable, nigh-undebuggable problems.
Here's an example:
In bunnyboy's SNES PowerPak firmware, there's an 8-byte long DP (= Direct Page) variable called "temp". He uses this variable as a quick/known-volatile data storage for like everything, including a scrolling subroutine executed during Vblank. What he didn't account for in his software design was the fact that NMI could fire at any time -- and I didn't realize/encounter any bugs either, at least not until I decided to use temp through temp+7 during active display for filename calculations. I was just stuck wondering why filenames randomly wouldn't show up at all in the file browser -- until I realized my (i.e., his) mistake, and made this commit. Everything's been working fine ever since.
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)
Re: SNES Splatoon (How do I shot HiROM?)
@Nicole
I don't speak of good practice
Each one is free to choose his technique, but that for me my game must end before the VBlank
So point b) never happens, and yet I don't make small a game.
And it reminds me of C language, a bad pointer = a program that does not work
But I want to know I'm doing that, so I wanted to have confirmation that the NMI = VBlank and so if my finished code before VBlank, the stack is not used really.
Of course I don't advise it.
Edit:
Ramsis is right, I have to save the temporary variable, and increase my security code on the buffer dma :/
I think it is easier than the finished code before VBlank.
I don't speak of good practice
Each one is free to choose his technique, but that for me my game must end before the VBlank
So point b) never happens, and yet I don't make small a game.
And it reminds me of C language, a bad pointer = a program that does not work
But I want to know I'm doing that, so I wanted to have confirmation that the NMI = VBlank and so if my finished code before VBlank, the stack is not used really.
Of course I don't advise it.
Edit:
Ramsis is right, I have to save the temporary variable, and increase my security code on the buffer dma :/
I think it is easier than the finished code before VBlank.
Re: SNES Splatoon (How do I shot HiROM?)
You're absolutely right, I had completely forgotten about/overlooked that fact.Ramsis wrote:Once again, P (processor status) is saved automatically when an interrupt fires, and restored automatically by the rti opcode. In other words, there's normally no need to do php / plp at the beginning and end of your IRQ/NMI handler. :wink:koitsu wrote:In other words: back up your registers (including P, D, B, or anything else you tweak in your NMI routine), and restore them (in the correct order) before doing rti. The end.
Re: SNES Splatoon (How do I shot HiROM?)
In my experience with bass:psycopathicteen wrote:I wonder why there's all this fuss about ca65? Byuu has a very nice assembler on his website, it has none of that segment crap on it. It's pretty much tell the assembler what kind of ROM it is, and what CPU address to start the code at, and that's all.
- Putting white space where it shouldn't be on accident freezes up the program; bass is the only assembler that seems to have this problem.
Opcode sizes have to be watched carefully by the user; ca65 manages this for you.
The error messages don't say a whole lot.
Comments are done with //, so snippets from other people (even yourself) with comments from ANY other assembler will throw you off.
Where's the enum feature? It isn't very convenient, having to map out variable offsets on your own through defines.
-
psycopathicteen
- Posts: 3001
- Joined: Wed May 19, 2010 6:12 pm
Re: SNES Splatoon (How do I shot HiROM?)
From what I hear, it sounds like if you want to, say write to $7f0000, instead of writing this:
lda #$55
sta $7f0000
You'd write this:
lda #$55
sta BSS7F_SEGMENT+$0000
or some crazy stuff like that.
lda #$55
sta $7f0000
You'd write this:
lda #$55
sta BSS7F_SEGMENT+$0000
or some crazy stuff like that.
Re: SNES Splatoon (How do I shot HiROM?)
Assuming BSS 7F is a segment that starts at $7f0000, you'd declare like this:psycopathicteen wrote:From what I hear, it sounds like if you want to, say write to $7f0000, instead of writing this:
lda #$55
sta $7f0000
You'd write this:
lda #$55
sta BSS7F_SEGMENT+$0000
or some crazy stuff like that.
Code: Select all
.segment "BSS 7F" : far
variable: .dsb 1Code: Select all
lda #$55
sta variableCode: Select all
lda #$55
sta $7f0000