(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:
Okay, so this does:
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:
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.)
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
- Declare a variable nmis at $00 in the zeropage
- On every nmi, increment it by 1
- During every cycle of the main loop, check it until it's value is >0
- Once it's >0, copy the OAM and then make sure the screen is enabled
- Normally, it would miss an execution cycle every 256 frames, when the INC NMIS call rolls over from FF to 00
- It seems weird that the main loop does stuff on the PPU - shouldn't the NMI Handler do all of that?
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
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
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