Page 2 of 2

Posted: Mon Jul 10, 2006 4:36 pm
by nineTENdo
Ok my stupid brain finally understands how NMI works. WRITE SCREEN, VBLANK (NMI EXECUTION ON 7.2000 set), REPEAT. My Question is how do how do i impliment a code to keep vblanking. ive set my 7.2000 written simple ADC #$10 to move a sprite on #$4014. And still nothing. im thinking becasue the damn thing isnt vblanking. ive seen some code were vblank just loops in main loop. What should i do. So far ive got my backround to flicker and change color. well heres my code.

Code: Select all

nmi
	pha
	txa
	pha
	tya
	pha
		
	lda X_POS
	adc #$10
	sta X_POS
	Lda #$7
	sta $4014
	Lda #$00
	STA $2005
	STA $2005

	
	pla
	tay
	pla
	tax
	pla
	
	rti
Thanks in advance,
EL

Posted: Wed Jul 12, 2006 4:07 pm
by Disch
Not sure I fully understand your question, but maybe I can help fill in the blanks.

how do i impliment a code to keep vblanking
VBlank isn't a thing you can control. VBlank happens roughly 60 times per second at steady intervals regardless of what your code is doing (one VBlank every ~29830 CPU cycles, which is very roughly every ~7458 instructions, assuming an average of 4 cycles per instruction). VBlank will always happen whether you're ready for it or not... or whether you want it to or not.

An NMI (if enabled) is tripped at the very start of VBlank to notify your program that VBlank is happening. NMIs will always trip on every VBlank as long as both of the following are true:

- they're enabled ($2000.7 is set)
- you're not reading $2002 around the time VBlank starts

I doubt very much you're doing the latter. So if NMIs are not occuring for you, it must be because you have them disabled. Make sure that when you write to $2000, the high bit (bit 7: $80) is set.



Another potential reason for your problem is that your 'X_POS' variable is defined wrong. Where in memory is 'X_POS'? Like... what do you define it as? (you probably have a line somewhere that's "X_POS = something")

Posted: Wed Jul 12, 2006 6:33 pm
by nineTENdo
NMIs will always trip on every VBlank as long as both of the following are true:

- they're enabled ($2000.7 is set)
- you're not reading $2002 around the time VBlank starts
Well i have 7.2000 set at the PPU initialization instead of it being cleared. And my is at X_POS = 0703 and is refreshed with a LDA #$7 and $4014 store. And i think i might not be reading $2002 around the time VBlank starts. I dont how i would do that. It looks like i might be doing it but then again i not sure. im kinda confused on the whole reading from $2002. Does the 7. $2000 have to set or cleared when reading. Heres what i have can you tell how to point to it or can i just include it in the NMI.

Code: Select all

infinite: 
waitblank   lda $2002                   < this keeps my sprite moving 
	BPL waitblank                 and nice looking when i press A.
	
	lda #$01	
 	sta $4016
 	lda #$00
 	sta $4016 
	
	lda $4016
	and #1
	bne KEYDN
	lda $4016
	lda $4016  
	lda $4016  
	lda $4016
	lda $4016 
	lda $4016  
	lda $4016
	JMP infinite

KEYDN
	
	clc
	LDA Y_POS
	ADC #$75
	
	sta Y_POS
	CLC
	lda X_POS
	
	ADC #$40
	sta X_POS	
	lda #$7
	sta $4014
	BNE infinite
	jmp infinite
nmi
	pha
	txa
	pha
	tya
	pha
	
  lda X_POS 
   adc #$10 
   sta X_POS 
   Lda #$7 
   sta $4014 
   Lda #$00 
   STA $2005 
   STA $2005 
                pla
	tay
	pla
	tax
	pla
	
	rti

Posted: Wed Jul 12, 2006 6:57 pm
by Quietust

Code: Select all

waitblank   lda $2002
   BPL waitblank
You shouldn't be waiting on $2002 outside of your initialization code - it's not reliable, and on an NES it will result in missed frames.

To do it properly, you should use this instead:

Code: Select all

waitblank   lda gotnmi
   BEQ waitblank
   lda #0
   sta gotnmi
and, right after the

Code: Select all

   Lda #$00
   STA $2005
   STA $2005
in your NMI routine, insert

Code: Select all

   LDA #$01
   STA gotnmi
Oh, and declare "gotnmi" along with the rest of your variables.
This is what we talked about earlier about not polling $2002 to wait for VBLANK, but instead using a variable that you set whenever you get an NMI.

Posted: Wed Jul 12, 2006 7:19 pm
by nineTENdo
Quietust wrote: To do it properly, you should use this instead:

Code: Select all

waitblank   lda gotnmi
   BEQ waitblank
   lda #0
   sta gotnmi
and, right after the

Code: Select all

   Lda #$00
   STA $2005
   STA $2005
in your NMI routine, insert

Code: Select all

   LDA #$01
   STA gotnmi
What i dont understand is how $2002 gets worked into the code. I would think that it has to equal something or get stored.

But other than that i understand whats going.

Posted: Wed Jul 12, 2006 7:28 pm
by Quietust
nineTENdo wrote:What i dont understand is how $2002 gets worked into the code.
That's just it - you shouldn't be using $2002 (except for in your RESET code in order to wait 2 frames, since that's required).
nineTENdo wrote:I would think that it has to equal something or get stored.
It isn't a byte of memory - it's a memory-mapped I/O register. Its value changes on its own, and reading it performs other actions.

Posted: Wed Jul 12, 2006 7:33 pm
by nineTENdo
What would be the proper $2002 read a reset. Would this code be inclided at reset.

Code: Select all

waitblank   lda gotnmi 
   BEQ waitblank 
   lda #0 
   sta gotnmi

Posted: Wed Jul 12, 2006 7:43 pm
by Quietust
nineTENdo wrote:What would be the proper $2002 read a reset. Would this code be inclided at reset.

Code: Select all

waitblank   lda gotnmi 
   BEQ waitblank 
   lda #0 
   sta gotnmi
No - that doesn't use $2002.

Really, you should be able to figure this out by now.

Posted: Wed Jul 12, 2006 7:47 pm
by Disch
You misunderstood what I said before about $2002

NMIs will work reliably if you're NOT reading $2002. This means you SHOULDN'T be reading $2002 (since you want to be using NMIs)

But as Q is saying, you'll still want to use $2002 for waiting for the first two frames (when you wait for the PPU to warm up)

For that... you'll want to do something like this once at startup (at the start of your reset routine):

Code: Select all

: lda $2002
  bpl :-
: lda $2002
  bpl :-
Or if you're not using as nice of an assembler:

Code: Select all

wait1:
  lda $2002
  bpl wait1
wait2:
  lda $2002
  bpl wait2

But in your game logic, when you're waiting for VBlank, you should not be reading $2002. To wait for the next VBlank, make sure NMIs are enabled, and then just wait for your NMI to trip.

Posted: Wed Jul 12, 2006 8:05 pm
by nineTENdo
Quietust wrote:
Really, you should be able to figure this out by now.
its not clicking. But heres what i have.

Code: Select all

Start:  
	sei
	cld
	jsr WVB
	jsr LDPAL
	JSR LDNT
	
NOTHING
	JMP NOTHING
WVB	
wait1: 
  	lda $2002 
  	bpl wait1 
wait2: 
  	lda $2002 
  	bpl wait2 
	RTS


LDPAL	      
	ldx #$00   

	lda #$3F    
	sta $2006   
	lda #$00    
	sta $2006

loadpal:                
	lda tilepal, x 
	sta $2007       
	inx             
	cpx #32         
	bne loadpal  
	rts   
LDNT
   	lda #$20
  	sta $2006
   	sta $2006
   	ldx #$00


loadNames1:
   	lda ourMap, X
   	sta $2007
   	inx
   	bne loadNames1

loadNames2:
   	lda ourMap+$100, X
   	sta $2007
   	inx
   	bne loadNames2

loadNames3:
   	lda ourMap+$200, X
   	sta $2007
   	inx
   	bne loadNames3

loadNames4:
   	lda ourMap+$300, X
   	sta $2007
   	inx
   	cpx #$80
   	bne loadNames4

	lda #%1001000  
	sta $2000       
	lda #%00011110 
	sta $2001 

	lda #$02
	sta $0701
	rts



waitblank   
	lda gotnmi 
   	BEQ waitblank 
   	lda #0 
   	sta gotnmi
KEYDN
	
	clc
	LDA X_POS
	ADC #$10
	sta X_POS
	lda #$7
	sta $4014
	
	rts
	

nmi
	pha
	txa
	pha
	tya
	pha
	
	lda #$01
	sta gotnmi
	lda #$00
	Sta $2005
	Sta $2005
	jsr waitblank

	
	pla
	tay
	pla
	tax
	pla
	
                rti

Posted: Wed Jul 12, 2006 8:08 pm
by Quietust

Code: Select all

   lda #%1001000 
   sta $2000       
   lda #%00011110
   sta $2001 
You're missing one bit somewhere in your write to $2000...

Posted: Wed Jul 12, 2006 8:13 pm
by nineTENdo
EUURRREEKKAAAAAA!!!!!!

Thanks Yall:)