This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Filled second nametable, it blinks occasionally

Filled second nametable, it blinks occasionally
by on (#120753)
...when it shouldn't. Probably again my fault but well... Here's code:
Code:
; Russian Roulette game for NES
; Copyright 2010 Damian Yerrick
;
; Copying and distribution of this file, with or without
; modification, are permitted in any medium without royalty
; provided the copyright notice and this notice are preserved.
; This file is offered as-is, without any warranty.
;
SCROLLY=$28
NMICOUNTER = $03
.include "nes.h"
.p02

.segment "ZEROPAGE"

.segment "INESHDR"
  .byt "NES",$1A
  .byt 1  ; 16 KiB PRG ROM
  .byt 1  ; 8 KiB CHR ROM
  .byt 0  ; horizontal mirroring; low mapper nibble: 0
  .byt 0  ; high mapper nibble: 0

.segment "VECTORS"
  .addr nmi, reset, irq

.segment "CODE"

; we don't use irqs yet
.proc irq
  rti
.endproc

.proc nmi
   ;skipping NMI if $05 is set to $FF
   lda $05
   cmp #$FF
   beq eop
   ; Added this line to reset PPU address latches
   bit PPUSTATUS
   lda $28
   clc
   adc #$01
   sta SCROLLY
   lda #$00
   sta PPUSCROLL
   lda SCROLLY
   sta PPUSCROLL
   cmp #239
   bne eop
   jmp reset_scroll
   eop:
   inc NMICOUNTER
  rti
   reset_scroll:
   lda #00
   sta SCROLLY
   lda #%00000010
   eor $25
   sta $25
   sta PPUCTRL
   rti
.endproc



.proc reset
  sei
  ; Acknowledge and disable interrupt sources during bootup
  stx PPUCTRL    ; disable vblank NMI
  stx PPUMASK    ; disable rendering (and rendering-triggered mapper IRQ)
  lda #$40
  sta $4017      ; disable frame IRQ
  stx $4010      ; disable DPCM IRQ
  bit PPUSTATUS  ; ack vblank NMI
  bit $4015      ; ack DPCM IRQ
  cld            ; disable decimal mode to help generic 6502 debuggers
                 ; http://magweasel.com/2009/08/29/hidden-messagin/
  dex            ; set up the stack
  txs

  ; Wait for the PPU to warm up (part 1 of 2)
vwait1:
  bit PPUSTATUS
  bpl vwait1

  ; While waiting for the PPU to finish warming up, we have about
  ; 29000 cycles to burn without touching the PPU.  So we have time
  ; to initialize some of RAM to known values.
  ; Ordinarily the "new game" initializes everything that the game
  ; itself needs, so we'll just do zero page and shadow OAM.
  ldy #$00
  lda #$F0
  ldx #$01
clear_zp:
  sty $00,x
  inx
  bne clear_zp
  ; disabling NMI
  lda #$FF
  ;sta $05
 
  ; the most basic sound engine possible
  ;lda #$0F
  ;sta $4015

  ; Wait for the PPU to warm up (part 2 of 2)
vwait2:
  bit PPUSTATUS
  bpl vwait2

  ; Draw HELLO WORLD text
  jsr drawHelloWorld
  jsr drawface
  ;setting $00 to detect "soft" reset
  lda #$12
  sta $00
  ; Turn screen on
  lda #0
  sta PPUSCROLL
  sta PPUSCROLL
  lda #VBLANK_NMI|BG_1000
  sta $25
  sta PPUCTRL
  lda #BG_ON
  sta PPUMASK


mainLoop:
  jmp mainLoop
.endproc


.proc cls
  lda #VBLANK_NMI
  sta PPUCTRL
  sta $25
  lda #$20
  ldx #$00
  stx PPUMASK
  sta PPUADDR
  stx PPUADDR
  ldx #240
:
  sta PPUDATA
  sta PPUDATA
  sta PPUDATA
  sta PPUDATA
  dex
  bne :-
  ldx #64
  lda #0
:
  sta PPUDATA
  dex
  bne :-
  rts
.endproc

.proc drawHelloWorld
  jsr cls

  ; set monochrome palette
  lda #$3F
  sta PPUADDR
  lda #$00
  sta PPUADDR
  ldx #8
:
   lda $00
   cmp #$12
   beq resetpal
  lda #$11
  sta PPUDATA
  sta PPUDATA
  lda #$28
  sta PPUDATA
  lda #$31
  sta PPUDATA
  jmp contloading
resetpal:
   lda #$DE
  sta PPUDATA
  sta PPUDATA
  lda #$10
  sta PPUDATA
  lda #$30
  sta PPUDATA
contloading:
  dex
  bne :-
   
  ; load source and destination addresses
  lda #>helloWorld
  sta 1
  lda #<helloWorld
  sta 0
  lda #$20
  sta 3
  lda #$62
  sta 2
  ; fall through
.endproc
.proc printMsg
dstLo = 2
dstHi = 3
src = 0
  lda dstHi
  sta PPUADDR
  lda dstLo
  sta PPUADDR
  ldy #0
loop:
  lda (src),y
  beq done
  iny
  bne :+
  inc src+1
:
  cmp #10
  beq newline
  sta PPUDATA
  bne loop
newline:
  lda #32
  clc
  adc dstLo
  sta dstLo
  lda #0
  adc dstHi
  sta dstHi
  sta PPUADDR
  lda dstLo
  sta PPUADDR
  jmp loop
done:
  rts
.endproc

.proc drawface
   lda PPUSTATUS
   lda #$2C
   sta PPUADDR
   lda #$00
   sta PPUADDR
   ldy #$00
   loop:
   lda face,y
   sta PPUDATA
   iny
   sty $A1
   lda $A1
   cmp #160
   bne loop
   ldy #00
   loop2:
   lda face2,y
   sta PPUDATA
   iny
   sty $A1
   lda $A1
   cmp #160
   bne loop2
   ldy #00
   loop3:
   lda face3,y
   sta PPUDATA
   iny
   sty $A1
   lda $A1
   cmp #160
   bne loop3
   ldy #00
   loop4:
   lda face4,y
   sta PPUDATA
   iny
   sty $A1
   lda $A1
   cmp #160
   bne loop4
   ldy #00
   loop5:
   lda face5,y
   sta PPUDATA
   iny
   sty $A1
   lda $A1
   cmp #160
   bne loop5
   ldy #00
   loop6:
   lda face6,y
   sta PPUDATA
   iny
   sty $A1
   lda $A1
   cmp #160
   bne loop6
   rts
.endproc

.segment "RODATA"
helloWorld:
  .byt 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,"Hello, player!",10,"I'd like to give you this game",10,"to play",10,"       this with your friends!",0
face:
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0
face2:
  .byt 0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0
face3:
  .byt 0,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,2,0,0,2,2,2,2,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
face4:
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
face5:
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
face6:
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,"P","R","E","S","S",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,"S","T","A","R","T",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0


and the rom:
Re: Filled second nametable, it blinks occasionally
by on (#120757)
You are setting X scroll to 0 and leaving Y scroll at 239 when you reach Y = 239.
You should also be checking 240 instead of 239.
Re: Filled second nametable, it blinks occasionally
by on (#120787)
When I check for 240, it stops for one frame which means not smooth scroll. And for the second I have only one thing to say: Whoops!
Re: Filled second nametable, it blinks occasionally
by on (#120788)
No worries. NES development has a lot of woopses involved :) More experienced developers don't necessarily have fewer, they just get better at debugging them on their own. I think you're skill is coming along very quickly comparatively. Do you have any prior experience with assembly?
Re: Filled second nametable, it blinks occasionally
by on (#120790)
Not with actual processor assembly, only with Notch's DCPU16, but I have experience with programming in general. Bitwise operators, binary/hex, things like that.
Re: Filled second nametable, it blinks occasionally
by on (#120797)
darkhog wrote:
...when it shouldn't. Probably again my fault but well... Here's code:
Code:
.proc nmi
   ;skipping NMI if $05 is set to $FF
   lda $05
   cmp #$FF
   beq eop



Careful here. I know your not there yet, but when you are: If your main thread isn't ready, and you exit NMI, you have changed the accumulator.. your main thread will have no idea that it has changed. You could save the accumulator first, but you could also use BIT to test the flag variable and branch on the N flag. A, X and Y will not be changed and RTI will restore the status register.
( http://www.obelisk.demon.co.uk/6502/reference.html#BIT )

I understand you are learning, so hopefully this helps as well:

Code:
   
   lda $28
   clc
   adc #$01
   sta SCROLLY
   lda #$00
   sta PPUSCROLL
   lda SCROLLY
   sta PPUSCROLL


I like to optimize, or at least attempt to. Consider taking advantage of the other registers to optimize a bit, avoid incrementing with the accumulator:

Code:
   
   ldx SCROLLY
   inx
   stx SCROLLY
   lda #$00
   sta PPUSCROLL
   stx PPUSCROLL


or maybe better yet:

Code:
   
   inc SCROLLY
   lda #$00
   sta PPUSCROLL
   lda SCROLLY
   sta PPUSCROLL
Re: Filled second nametable, it blinks occasionally
by on (#120819)
Thanks for the tips!
Movax12 wrote:
Careful here. I know your not there yet, but when you are: If your main thread isn't ready, and you exit NMI, you have changed the accumulator.. your main thread will have no idea that it has changed. You could save the accumulator first, but you could also use BIT to test the flag variable and branch on the N flag. A, X and Y will not be changed and RTI will restore the status register.
( http://www.obelisk.demon.co.uk/6502/reference.html#BIT )

Or I could just reset accumulator at the start of main loop ;)

Movax12 wrote:
I understand you are learning, so hopefully this helps as well:

Code:
   
   lda $28
   clc
   adc #$01
   sta SCROLLY
   lda #$00
   sta PPUSCROLL
   lda SCROLLY
   sta PPUSCROLL


I like to optimize, or at least attempt to. Consider taking advantage of the other registers to optimize a bit, avoid incrementing with the accumulator:

Code:
   
   ldx SCROLLY
   inx
   stx SCROLLY
   lda #$00
   sta PPUSCROLL
   stx PPUSCROLL


or maybe better yet:

Code:
   
   inc SCROLLY
   lda #$00
   sta PPUSCROLL
   lda SCROLLY
   sta PPUSCROLL

Thanks, will use that. Dunno why I didn't think about this before ;).

//edit: Also my programming is working like that: First I make sure code does work, then I optimize if it runs at unsatisfactory speed.
Re: Filled second nametable, it blinks occasionally
by on (#120822)
Quote:
Or I could just reset accumulator at the start of main loop ;)

Err... no, that wouldn't fix what he's describing, and makes assumptions like "the program will never take longer than a frame to run." (A bad assumption to make on NES.) The NMI interrupts the main loop to run itself.

Here's a simple example: Say you've got a loop where you're storing zero a lot of times. Something like this.

Code:
lda #$00
tay
loop:
sta someplace,y
dey
bne loop


You NMI fires right in the middle of this loop. Your NMI changes A somehow (let's say to #$FF). When you RTI from the NMI back to your loop, #$FF is now in A. Your loop has no idea that happened and is now storing #$FF to someplace,y instead of #$00 as you expect. This can result in hard to find bugs. So the idea is to save your registers (A, X and Y) at the beginning of the NMI, so that you can restore them to what what your code expects them to be before you return with RTI. Then the code can resume as if nothing has changed. Alternatively, straight up don't change them UNLESS the main loop is ready, which is why Movax suggested to use BIT for that test. BIT doesn't change A.

Try not to dismiss those trying to help. I may be reading too much into it, but that wink was like, "Yeah, yeah I know that." When there's more to the story.
Re: Filled second nametable, it blinks occasionally
by on (#120823)
Ah, okay... Will save registers to memory and restore at end of nmi like a good boy ;).