Page 1 of 1

I guess this is basically my questions thread now

Posted: Tue Mar 20, 2007 12:53 am
by Jeff Garneau
For some reason, in my program, an IRQ is happening. I'm not clear on why it's happening, as when i go to debug in fceuxdsp, it says that i'm in my program's main stalling loop. i hit "step into" over and over again, and it loops normally, hitting no breakpoints. of course, an IRQ is pending, so it keeps going to my IRQ handler, which currently consists of an RTI instruction. so, how do you turn off an IRQ anyways? SEI and CLI don't seem to stop it. it seems to be stopping my vblank routine from running (though i suppose it shouldn't as NMI takes precedence over IRQ, right?)

my code and .nes file are here:

Posted: Tue Mar 20, 2007 2:49 am
by hap
I see you use a CLI to enable vblank NMI? SEI and CLI only affect IRQ, not NMI. If you're never going to use IRQs, the simplest solution would be a SEI at the start of your program (like you have right now), and never ever use CLI.

The cleaner solution would be to use SEI like above, and disable every IRQ 'generator', like the APU frame sequencer IRQ.

Posted: Tue Mar 20, 2007 6:21 am
by tepples
Another thing to watch out for is that SEI and CLI are reversed in meaning compared to x86.

Posted: Tue Mar 20, 2007 10:16 am
by dvdmth
The start of every program should execute SEI (to mask IRQ's), write $40 or $C0 to $4017 (to disable frame IRQ's), and write $00 to $4010 (to disable DMC IRQ's). If you're using a mapper that can generate IRQ's (such as the MMC3 and MMC5), be sure to perform whatever steps are required to disable IRQ's for the respective mapper.

These steps are common programming practice - never assume the state of anything. Until you explicitly disable all potential IRQ sources, you cannot safely assume that IRQ's won't occur. This advice is generic for all platforms, not just the NES.

Posted: Tue Mar 20, 2007 11:50 am
by Jeff Garneau
OK. I've got an SEI at the beginning of my program and I never clear the interrupt bit. Only thing is, my NMI doesn't seem to be going off more than once. Right now, it just draws the first letter of text (it's supposed to draw a letter every frame). I set up a method that mimics what happens when vblank occurs, and when I force the PC to that method from the main loop it draws the next letters just fine. I guess when I do that it's actually outside of vblank, but for some reason fceuxdsp lets me do it. here's my vblank code:

Code: Select all

frame'update:
	lda mode ; if it's zero it means there is a new letter
	cmp #$00 ; waiting to be placed in vram
	beq gotoghost ; debug mode has shown that this actually gets set to 0
	bne dont
gotoghost:
	jsr ghostppu
dont:
	rts

vblank:    ; this is what $FFFA points to.
        jsr frame'update
	rti
irq:    
	rti

ghostppu:
	lda $2001
	and #%11100111
	sta $2001 ; turn off ppu

	lda vramlo
	sta $2006
	lda vramhi
	sta $2006


	lda nextletter
	sta $2007

	lda #$00
	sta $2005
	sta $2005
	lda $2000
	sta $2000
	lda $2001
	ora #%00011010
	sta $2001
	lda #$01
	sta mode
	rts
here's my main loop (callghostppu never gets called unless i manually set the PC):

Code: Select all

mainloop:
	ldx textindex
	lda text, x
	cmp #$FF    ; i use this to note when my text is finished writing.
	beq mainloopdone

	sta nextletter
	inc textindex
	inc vramhi
	lda #$00
	sta mode
	
mainloopdone:
	lda mode
	cmp #$01
	beq mainloop
	jmp mainloopdone

callghostppu:
	jsr frame'update
	jmp mainloopdone
the updated code and .nes file can be seen here:

thanks in advance

Posted: Tue Mar 20, 2007 2:01 pm
by never-obsolete

Code: Select all

ghostppu:
	lda $2001
	and #%11100111
	sta $2001 ; turn off ppu

	lda vramlo
	sta $2006
	lda vramhi
	sta $2006


	lda nextletter
	sta $2007

	lda #$00
	sta $2005
	sta $2005
	lda $2000
	sta $2000<----------------------------------
	lda $2001
	ora #%00011010
	sta $2001
	lda #$01
	sta mode
	rts
set a breakpoint at $C170 and you'll see that $00 is the last byte written to $2000, effectively turning NMI generation off.

i would also store the last values written to $2000/$2001 in variables rather then reading them back.

Posted: Tue Mar 20, 2007 6:03 pm
by Jeff Garneau
sweet! that totally worked!

now i just have to fix every other problem and code a million more things!

Posted: Tue Mar 20, 2007 11:01 pm
by blargg
Like saving and restoring register(s) modified by your NMI handler. Having A changed at random points in your code is very hard to debug...

Posted: Thu Mar 22, 2007 12:28 pm
by Jeff Garneau
that's simple, though. having an NMI like this:

Code: Select all

vblank:
   pha
   txa
   pha
   tya
   pha
   ;NMI subroutines
   pla
   tay
   pla
   tax
   pla
   rti
will handle it, right?

By the way, can you tell me why

Code: Select all

.segment zp
.org $0000


.space mode 1
.space vramhi 1
.space vramlo 1
.space textindex 1
.space nextletter 1
.space curr2000 1
.space curr2001 1
.advance $0010
produces a bunk rom but commenting out the .advance makes it work? i'm using p65 here. when i go to debug with that, its a rom that's basically all zeros (even in $C000), with a few FFs here and there. dunno why that ain't working.

Posted: Thu Mar 22, 2007 3:34 pm
by blargg
Yes, that pushing/popping code is the simplest correct way to save and restore all registers properly. While on the subject, the status flags are automatically pushed on the stack by the processor before entering your interrupt handler, and RTI restores them from the stack, so a php...plp would be redundant and pointless.