Quantcast
Channel: nesdev.org
Viewing all articles
Browse latest Browse all 746

Trying to understand vw3 and nmis in pinobatch/nrom-template

$
0
0
(Edit: I figured out the main misunderstanding, see my second reply. So my only question is "Why do this in main instead of the nmi_handler and get rid of nmis/vw3 completely")

Not sure if I should ask here or open a GitHub issue, but I figure that at least some of you have looked at this template in depth, and I don't want to badger the author. It's Damian Yerrick's template for an NROM game: https://github.com/pinobatch/nrom-template

I know it's a simple template/example, but I want to make sure that I 100% understand it before moving forward with more complex stuff.

So, there is a variable nmis, which is set in zeropage, incremented in the NMI handler, and checked in the main game loop:

Code:

; Truncated from the original, see main.s.segment "ZEROPAGE"nmis:          .res 1.segment "CODE".proc nmi_handler  inc nmis  rti.endproc.proc mainforever:  jsr run_dma_and_read_pads  ; Good; we have the full screen ready.  Wait for a vertical blank  ; and set the scroll registers to display it.  lda nmisvw3:  cmp nmis  beq vw3    ; Copy the display list from main RAM to the PPU  lda #0  sta OAMADDR  lda #>OAM  sta OAM_DMA    ; Turn the screen on  ldx #0  ldy #0  lda #VBLANK_NMI|BG_0000|OBJ_1000  sec  jsr ppu_screen_on  jmp forever; And that's all there is to it..endproc
Okay, so this does:
  1. Declare a variable nmis at $00 in the zeropage
  2. On every nmi, increment it by 1
  3. During every cycle of the main loop, check it until it's value is >0
  4. Once it's >0, copy the OAM and then make sure the screen is enabled
This seems weird, for two reasons:
  1. Normally, it would miss an execution cycle every 256 frames, when the INC NMIS call rolls over from FF to 00
  2. It seems weird that the main loop does stuff on the PPU - shouldn't the NMI Handler do all of that?
The first point is answered pretty quickly: The code that does read_pads just parties on ZeroPage location $00:

Code:

; pads.s.proc read_pads; This is actually nmiscontroller1 = $0000; Do a whole bunch of stuff with controller1, like rol controller1; At the end of this method, controller1 aka. nmis aka. $00 will be 0rts.endproc
I assume this is deliberate: Instead of using two bytes of zeropage RAM, the template just uses location $00 for two different purposes: First by the read_pads method, which as a side effect resets it to 0. And then the nmi_handler increments it to 1. So now, the vw3 loop is guaranteed to be a spinlock: Wait here until an nmi occurs (nmis from 0 to 1 in the nmi_handler), and then in the next cycle, it'll reset to 0 automatically.

Am I correct with this assumption that this is deliberate, and that moving the nmis variable to a different memory location where the gamepad read logic doesn't reset it to 0 every frame would actually introduce a bug? (I've tested it, and it does go from $00 all the way to $FF before resetting, instead of just flip-flopping between $00 and $01 (and whatever temporary state read_pads puts it into during its execution)) It does make sense, but I want to make sure to properly understand this code.

if that is correct, I'm inclined to explicitly set it to clarity:

Code:

vw3:  cmp nmis  beq vw3    ; Copy the display list from main RAM to the PPU  lda #0  sta nmis ; Explicitly reset nmis to 0 here, to never rely on the read_pads code doing it  sta OAMADDR  lda #>OAM  sta OAM_DMA
That leaves the second question: Is there a reason this is done in the main loop at all? If I remove the vw3 loop and move all the code from "lda #0" until "jmp forever" to the nmi_handler, it still all seems to work. I can see why it's done for clarity (so the main loop still reads nicely and the nmi_handler is much simpler, rather than splitting up the main game code into two separate places), but I wonder if there's a technical reason why you wouldn't want to do the OAM Copy in the NMI Handler?

I can see the potential that a second NMI occurs, but I don't think it should since the code after the vw3 label is guaranteed to run after an nmi finished, and unless I'm exceeding the VBLANK Cycle budget, there should be no timing issues.

(Sorry, this was a long post, I hope the question makes sense.)

Statistics: Posted by MenhirMike — Mon Jun 17, 2024 8:04 pm — Replies 2 — Views 84



Viewing all articles
Browse latest Browse all 746

Trending Articles