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

Pallete affects scroll value

Pallete affects scroll value
by on (#200402)
Hello, I have a question about the pallet and the screen. Every 6 frames I update the pallete, the scroll value gets affected temporally. How can you fix this?

HERE'S THE CODE:
Code:
NMI:

  INC scroll
   ; add one to our scroll variable each frame


NTSwapCheck:
  LDA scroll ; check if the scroll just wrapped from 255 to 0
  BNE NTSwapCheckP2 
NTSwap:
  LDA nametable         ; load current nametable number (0 or 1)
  EOR #$01              ; exclusive OR of bit 0 will flip that bit
  STA nametable         ; so if nametable was 0, now 1
                        ;    if nametable was 1, now 0
NTSwapCheckP2:


NTSwapCheckP2:
  LDA scrolly            ; check if the scroll just wrapped from 255 to 0
  BNE NTSwapCheckP3

NTSwap2:
  LDA nametabley         ; load current nametable number (0 or 1)
  EOR #$01              ; exclusive OR of bit 0 will flip that bit
  STA nametabley         ; so if nametable was 0, now 1 

NTSwapCheckP3:
 
 
 
NewAttribCheck:
  LDA scroll
  AND #%00011111            ; check for multiple of 32
  BNE NewAttribCheckDone    ; if low 5 bits = 0, time to write new attribute bytes
  jsr DrawNewAttributes
NewAttribCheckDone:

   
   
NewColumnCheck:
  LDA scroll
  AND #%00000111            ; throw away higher bits to check for multiple of 8
  BNE NewColumnCheckDone    ; done if lower bits != 0
  JSR DrawNewColumn         ; if lower bits = 0, time for new column
 
  lda columnNumber
  CMP #$FE
  BCC DT9
 
  LDA #$00
  STA scroll+2
 
 
DT9:
 
  lda columnNumber
  clc
  adc #$01             ; go to next column
  and #%11111111       ; only 256 columns of data, throw away top bit to wrap
  sta columnNumber
 
  lda scroll+2
  clc
  adc #$01
  STA scroll+2
 
 
  JSR Scrollcheck
   
 
NewColumnCheckDone:

 
 
 
  LDA #$00
  STA $2003       
  LDA #$02
  STA $4014       ; sprite DMA from $0200
 
 
  JSR LoadPalettes2

 
 
  LDA #$00
  STA $2006        ; clean up PPU address registers
  STA $2006
 
 
 
  LDA scroll
  STA $2005        ; write the horizontal scroll count register

  LDA scrolly         ; no vertical scrolling
  STA $2005
 
 
   
 
 
 
  ;;This is the PPU clean up section, so rendering the next frame starts properly.
  LDA #%10010000   ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
  ORA nametable    ; select correct nametable for bit 0
  STA $2000
 
  LDA #%00011110   ; enable sprites, enable background, no clipping on left side
  STA $2001
 
 

 
  JSR Updating
  JSR Gravity
  JSR ReadController1
 
 
 
 
  LDA #$00
  STA T
 
 
 
  LDA #$00
  STA D
 
  LDA #$00
  STA D+1
 

 LDA buttons
  AND #%10000000 ; only look at bit 0
  BEQ ReadADone   ; branch to ReadADone if button is NOT pressed (0)
                 
 
 
  LDA JumpState
  CMP #$01
  BCS ReadADone
 
  LDA #$01
  STA JumpState
 
 
 
 
 

  ; save sprite X position
ReadADone: 
 
 LDA buttons
 AND #%00000001 ; only look at bit 0
  BEQ ReadRightDone   ; branch to ReadADone if button is NOT pressed (0)
                     
 
  LDA #$01
  STA D
 
  LDA player       
  CLC             
  ADC #$01       
  STA player
 
  LDA #$00
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadRightDone:

 LDA buttons
 AND #%00000010 ; only look at bit 0
  BEQ ReadLeftDone   ; branch to ReadADone if button is NOT pressed (0)
                 
  LDA player       
  SEC             
  SBC #$01       
  STA player
 
  LDA #$01
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadLeftDone:

 
 LDA buttons
 AND #%00100000 ; only look at bit 0
  BEQ ReadUpDone
 
 
 
 
  LDA buttons
  AND #%00010000
 
   
 
  LDA gamestate
  CLC
  ADC #$01
  STA gamestate
 
ReadUpDone:
; run normal game engine code here
 ; reading from controllers, etc
 
 
 
  RTI              ; return from interrupt
 
 
 
 

DrawNewColumn:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$20          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  JSR levelselect
 

DrawColumn:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E         ; copy 30 bytes
  LDY #$1E
DrawColumnLoop:
  LDA [sourceLow], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop

 


 
DrawNewColumn2:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow2    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$28          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28 changes what loads the name table in the bottem name table in
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber2  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow2
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh2
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

DrawColumn2:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E              ; copy 30 bytes
  LDY #$1E
DrawColumnLoop2:
  LDA [sourceLow2], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop2

 

 
  RTS
 
 

 
 
DrawNewAttributes:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(attribData)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(attribData)
  STA sourceHigh

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone
 
  LDA columnLow         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow
  JMP DrawNewAttributesLoop
DrawNewAttributesLoopDone:

  RTS

DrawNewAttributes2:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop2
  LDA columnHigh2
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow2], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone2
 
  LDA columnLow2         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow2
  JMP DrawNewAttributesLoop2
DrawNewAttributesLoopDone2:


 


  rts

; skip the update function
LoadPalettes2:


 
 
  LDA #$00
  STA Timer1+5
 
  LDA #$00
  STA Timer1+6
 
  LDX #$00
 
LP2:
 
  LDA #$3F
  STA $2006
  LDA Timer1+6
  STA $2006
 
  LDA paletteswap , x
  STA $2007
   
 
 
 
  INX
 
  INC Timer1+5
 
  INC Timer1+6
 
  LDA Timer1+5
  CMP #$20
  BEQ Fin
 
 
  JMP LP2
 
Fin:


 
 
  RTS
 
 

I have also read this:
https://wiki.nesdev.com/w/index.php/The_frame_and_NMIs
And I don't Understand what he mean to do for lda needppureg
Please first explain what the problem is before showing the code.
Thanks.
Re: Pallete affects scroll value
by on (#200404)
The PPU is weird. The PPU Address ($2006) shares bits with the scroll ($2005). Writing to one affects the other.

After writing to the PPU, you must set a nametable(write to $2000), and set a scroll position (2 writes to $2005)


Edit. I think you are doing what i said.

Probably a timing issue. Writing outside V-blank.
Re: Pallete affects scroll value
by on (#200405)
Not sure if it's the culprit, but I see that you have "PPU cleanup" twice and one of them comes after your scroll updates.

I see some other bad things as well. You have logic at the beginning of your NMI handler, logic is better to have in the main loop, or after all graphic updates (OAM, VRAM and certain register updates) in the NMI, else it will steal vblank time. The NMI handler first needs to backup registers A, X and Y to stack (unless you are doing the all-in-NMI approach) then immediately do graphic updates. The order of the graphic updates is ideally something like this:
1) Check your render flag and skip all graphic updates if clear (read bellow)
2) Read $2002 to reset high/low latch
3) Sprite updates (OAM DMA)
4) Background updates
5) Palette updates
6) $2000 and $2001 updates
7) Scroll updates ($2005)
4, 5 and 6 can probably come in any order, but OAM DMA should be done early for PAL compatibility and Scroll should be updated last because PPU register writes affects the scroll register.

After all the graphic updates, you can have things that don't have to be in vblank, like sound updates or controller updates, though I heard controller updates are better to have in your main loop to avoid possible inconsistencies. Sound is best to be in NMI though since it ensures mostly constant tempo timing.

About the needppureg flag, he uses it whenever he has made changes to $2000 or $2001 in their buffers so that the NMI only updates them when the flag is set. I don't think it's really necessary to make them conditional separately. You should make the whole graphic update block conditional though. Have a render flag that is set at the end of each main loop and cleared at the end of each NMI. If the flag is not set, jump past all the graphic updates (but not sound and everything after that). That way there is no risk for drawing partly updated frames when the game lags.
Re: Pallete affects scroll value
by on (#200416)
What logic is at the main loop?
Re: Pallete affects scroll value
by on (#200417)
Everything in your NMI before the sprite DMA looks like logic to me (it does not write to VRAM, OAM or PPU registers, so it's not graphic updates). It should be in your main loop.

Is the main loop in your NMI? In that case it should come after the graphic updates, because the first part of the NMI always happens during the vblank interval, which is limited. The article you linked to explains this too.
Re: Pallete affects scroll value
by on (#200438)
Definitely writing to PPU outside V-blank. I dropped your code into a blank template, and put some breakpoints on when the final scroll setting is done. About every 8 frames, you are clear down to scanline 7, occasionally more, by the time you set the scroll for the screen. [I had to make some assumptions, since you didn't provide the entire source code, I might be off by a few lines]

Eliminating the line...
jsr LoadPalettes2 (you are updating the entire palette, every frame)
-I don't know why you said "Every 6 frames". It happens every frame.

...improves this quite a bit, but still hitting scanline 1 occasionally, which would shift the entire screen by 1 pixel. Jittery. If you tightened your code a bit (made loops slightly more efficient). You could probably avoid the scroll shift entirely.

A more ideal solution, would be to do most of the calculations before hand (outside of NMI). Load all updates into a buffer (also outside of NMI), and make a much more efficient system of writing to the PPU. Then you could put the palette updates back in.




EDIT: also...

[deleted some code advice, I didn't like my wording]

You need to be careful about which direction PPU writes are going. You specifically set it to +32 in the DrawColumn / DrawColumn2 subroutines, but that comes after the attribute table subroutine, and it's still set to +1 mode from the end of the NMI write to $2000 [I guess that won't cause a problem, now that I look at it]. Further, it is still in +32 mode (sometimes) when it gets to LoadPalettes2, which needs it to be in +1 mode.
Re: Pallete affects scroll value
by on (#200546)
Cool. :mrgreen:
1. Is updating the palette EVERY FRAME a bad thing and can it be done with buffering?
2 whuts buffering?
3 pla does What?
Also Would It help to give you the .nes file for reference?
Heres the new CODE:

Code:
LoadPalettes2:


  LDA #%00000000        ; set to increment +32 mode
  STA $2000
 
 
  LDA $2002             ; read PPU status to reset the high/low latch
 
 
  LDA #$00
  STA Timer1+5
  STA Timer1+6
 
  LDX #$00
 
LP2:
 
   
 
  LDA #$3F
  STA $2006
  LDA Timer1+6
  STA $2006
 
  LDA paletteswap , x
  STA $2007
   
 
 
 
  INX
 
  INC Timer1+5
 
  INC Timer1+6
 
  LDA Timer1+5
  CMP #$20
  BEQ Fin
 
 
  JMP LP2
 
Fin:


  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  RTS
 

NOW, to learn buffering.
Re: Pallete affects scroll value
by on (#200559)
1. Not a bad thing as long as it is updated in vblank, and yes buffering is the preferable way to do it. The palette isn't that big but if you are short on vblank time you could make a buffer system that only updates parts of the palette instead of the whole palette every time. You could also make a buffer system that updates nametable and palette together so that changing BG characters also changes their colours at the same time.

2. Buffering is keeping a copy of whatever you buffer (usually graphic updates) in a RAM area. You update this buffer in your game logic (main loop) and in the beginning of NMI (vblank) you just copy the contents of this buffer to VRAM/OAM etc. This way you can keep game logic and graphic updates separate. You are already buffering the OAM by using the RAM area $0200 to $02FF as an OAM buffer (or shadow OAM as they also call it). But DMA can only be used for OAM (sprite attributes), not for VRAM (nametable and palette), so you have to code a different buffer system for those. Updates to $2000 and $2001 should also be buffered in their own RAM registers so that they are also only changed in vblank.

3. PLA pulls the topmost value from the stack and puts it in the accumulator. If you have your main loop outside of NMI handler (in your RESET handler), you need to backup both the accumulator and the index registers X and Y on the stack at the start of your NMI handler and pull them out again in reverse order. PHA pushes the accumulator on to the stack but there are no instructions for pushing or pulling X or Y to or from stack, so you have to transfer X and Y into A first (using TXA/TYA when pushing and TAX/TAY after pulling):
Code:
NMI:
  pha
  txa
  pha
  tya
  pha                ;save A, X and Y to the stack

;(NMI code here)

  pla
  tay
  pla
  tax
  pla                ;restore A, X and Y from the stack
  rti

This is needed because the NMI is an interrupt that could happen at any time in your main loop, and since both main and NMI uses the registers it could mess up your code. You don't need to backup the status flags however, because they are backed up automatically whenever an interrupt occurs.

The NES file would help, but the whole source code would help more.
Re: Pallete affects scroll value
by on (#200607)
Code:
  .inesprg 1  ; 1x 16KB PRG code
  .ineschr 4   ; 1x  8KB CHR data
  .inesmap 4   ; mapper 0 = NROM, no bank swapping
  .inesmir 2   ; background mirroring
 

;;;;;;;;;;;;;;;
    .rsset $0000  ;;start variables at ram location 0
 

paletteswap     .rs 32
scroll     .rs 3
D     .rs 2
scrolly     .rs 1
gravity    .rs 1
buttons    .rs 1
gamestate  .rs 4
progress   .rs 1
buttonslay .rs 1
player     .rs 2
feet       .rs 1
jheight    .rs 1
pdirection .rs 5
grounded .rs 1
Frame .rs 1
Fr .rs 1
Timer1 .rs 12
ANT .rs 4
T .rs 1
Srt .rs 6

Ant .rs 1
L .rs 1
BCount .rs 16
JumpState .rs 3
nametable  .rs 1
nametabley  .rs 1  ;  ; which nametable to use, 0 or 1
columnLow  .rs 1  ; low byte of new column address
columnHigh .rs 1  ; high byte of new column address
sourceLow  .rs 1  ; source for column data
sourceHigh .rs 1
columnNumber .rs 1
columnNumber2 .rs 1
sourceLow2  .rs 1  ; source for column data
sourceHigh2 .rs 1
columnLow2  .rs 1  ; low byte of new column address
columnHigh2 .rs 1  ; hi


  ; which column of level data to



GROUND     = $B1  ;



;;;;;;;;;;;;;;;


  .bank 0
  .org $C000
 
  vblankwait:
  BIT $2002
  BPL vblankwait
  RTS
 
 
  RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40
  STX $4017    ; disable APU frame IRQ
  LDX #$FF
  TXS          ; Set up stack
  INX          ; now X = 0
  STX $2000    ; disable NMI
  STX $2001    ; disable rendering
  STX $4010    ; disable DMC IRQs
  lda #%00000001
  sta $4017 ;enable Square 1
 
    ;square 1
  lda #%00000000 ;Duty 10, Length Counter Disabled, Saw Envelopes disabled, Volume F
  sta $4000
   
  lda #$C9    ;0C9 is a C# in NTSC mode
  sta $4002   ;low 8 bits of period
  lda #$00
  sta $4003
 
   
  JSR vblankwait     

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0200, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
   JSR vblankwait   

 
LoadPalettes:
  LDA $2002    ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006    ; write the high byte of $3F00 address
  LDA #$00
  STA $2006    ; write the low byte of $3F00 address
  LDX #$00
LoadPalettesLoop:
  LDA palette, x        ;load palette byte
 
 
 
  STA $2007             ;write to PPU
  INX                   ;set index to next byte
  CPX #$20           
  BNE LoadPalettesLoop

  LoadPalettesLoop1:
  LDA palette, x        ;load palette byte
 
 
 
  STA paletteswap, x             ;write to PPU
  INX                   ;set index to next byte
  CPX #$20           
  BNE LoadPalettesLoop1   ;if x = $20, 32 bytes copied, all done
 
 
 
LoadPSprites:
 
 
  LDX #$00              ; start at 0
LoadSpritesLoopP:
  LDA Playersprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$08             ; Compare X to hex $20, decimal 32
  BNE LoadSpritesLoopP   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
 
LoadESprites:
 
 
  LDX #$00              ; start at 0
LoadSpritesLoopE:
  LDA Esprites, x        ; load data from address (sprites +  x)
  STA $0218, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX $FF            ; Compare X to hex $20, decimal 32
  BNE LoadSpritesLoopE   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
     
             
             

   
 
InitializeNametables:
  LDA #$01
  STA nametable
  LDA #$00
  STA scroll
  STA columnNumber
InitializeNametablesLoop:
  JSR DrawNewColumn
  ; draw bg column
  LDA scroll            ; go to next column
  CLC
  ADC #$08
  STA scroll
  INC columnNumber
  LDA columnNumber      ; repeat for first nametable
  CMP #$20
  BNE InitializeNametablesLoop
 
  LDA #$00
  STA nametable
  LDA #$00
  STA scroll
  JSR DrawNewColumn     ; draw first column of second nametable
  INC columnNumber
 
  LDA #$00              ; set back to increment +1 mode
  STA $2000
InitializeNametablesDone:


InitializeAttributes:
  LDA #$01
  STA nametable
  LDA #$00
  STA scroll
  STA columnNumber
InitializeAttributesLoop:
  JSR DrawNewAttributes     ; draw attribs
  LDA scroll                ; go to next column
  CLC
  ADC #$20
  STA scroll

  LDA columnNumber      ; repeat for first nametable
  CLC
  ADC #$04
  STA columnNumber
  CMP #$20
  BNE InitializeAttributesLoop
 
  LDA #$00
  STA nametable
  LDA #$00
  STA scroll
  JSR DrawNewAttributes     ; draw first column of second nametable
InitializeAttributesDone:

  LDA #$21
  STA columnNumber


 
 
  LDA #$10
  STA paletteswap
 
  LDA #$00
  STA JumpState
 
  LDA #$80
  STA player
 
  LDA #$FE
  STA scrolly
 
  LDA #$80
  STA player+1
 
  LDA #$08
  STA pdirection+1
 
  LDA #$06
  STA ANT
 
  LDA #$08
  STA ANT+1
 
  LDA #$0A
  STA ANT+2
 
  LDA #$06
  STA ANT+3
 
  LDA #$06
  STA Srt
 
  LDA #$01
  STA gamestate+1
 
 


 
 
 
  LDA #%10010000   ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
  STA $2000

  LDA #%00011000   ; enable sprites, enable background, no clipping on left side
  STA $2001

Forever:
  JMP Forever     ;jump back to Forever, infinite loop
 


NMI:



 

  INC scroll
   ; add one to our scroll variable each frame


NTSwapCheck:
  LDA scroll ; check if the scroll just wrapped from 255 to 0
  BNE NTSwapCheckP2 
NTSwap:
  LDA nametable         ; load current nametable number (0 or 1)
  EOR #$01              ; exclusive OR of bit 0 will flip that bit
  STA nametable         ; so if nametable was 0, now 1
                        ;    if nametable was 1, now 0



        ; so if nametable was 0, now 1 

NTSwapCheckP2:
 
  LDA #$00
  STA $2003       
  LDA #$02
  STA $4014       ; sprite DMA from $0200
 
NewAttribCheck:
  LDA scroll
  AND #%00011111            ; check for multiple of 32
  BNE NewAttribCheckDone    ; if low 5 bits = 0, time to write new attribute bytes
  jsr DrawNewAttributes
 
NewAttribCheckDone:

   
   
NewColumnCheck:
  LDA scroll
  AND #%00000111            ; throw away higher bits to check for multiple of 8
  BNE NewColumnCheckDone    ; done if lower bits != 0
  JSR DrawNewColumn         ; if lower bits = 0, time for new column
 
  lda columnNumber
  CMP #$FE
  BCC DT9
 
  LDA #$00
  STA scroll+2
 
 
DT9:
 
 
  lda columnNumber
  clc
  adc #$01             ; go to next column
  and #%11111111       ; only 256 columns of data, throw away top bit to wrap
  sta columnNumber
 
  lda scroll+2
  clc
  adc #$01
  STA scroll+2
 
 
  JSR Scrollcheck
   
 
NewColumnCheckDone:

 

  JSR LoadPalettes2
 
 
  LDA #$00
  STA $2006       
  STA $2006
 
   ;;This is the PPU clean up section, so rendering the next frame starts properly.
  LDA #%10010000   ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
  ORA nametable    ; select correct nametable for bit 0
  STA $2000
 
  LDA #%0001100^_^_[0   ; enable sprites, enable background, no clipping on left side
  STA $2001
 
 
 
  LDA scroll
  STA $2005        ; write the horizontal scroll count register

  LDA scrolly         ; no vertical scrolling
  STA $2005
 
 
   
 
 
 
 
 
 

 
  JSR Updating
  JSR ReadController1
 
 
 
 
  LDA #$00
  STA T
 
 
 
  LDA #$00
  STA D
 
  LDA #$00
  STA D+1
 

 LDA buttons
  AND #%10000000 ; only look at bit 0
  BEQ ReadADone   ; branch to ReadADone if button is NOT pressed (0)
                 
 
 
  LDA JumpState
  CMP #$01
  BCS ReadADone
 
  LDA #$01
  STA JumpState
 
 
 
 
 

  ; save sprite X position
ReadADone: 
 
 LDA buttons
 AND #%00000001 ; only look at bit 0
  BEQ ReadRightDone   ; branch to ReadADone if button is NOT pressed (0)
                     
 
  LDA #$01
  STA D
 
  LDA player       
  CLC             
  ADC #$01       
  STA player
 
  LDA #$00
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadRightDone:

 LDA buttons
 AND #%00000010 ; only look at bit 0
  BEQ ReadLeftDone   ; branch to ReadADone if button is NOT pressed (0)
                 
  LDA player       
  SEC             
  SBC #$01       
  STA player
 
  LDA #$01
  STA pdirection
 
  LDA #$01
  STA T
  ; save sprite X position
ReadLeftDone:

 
 LDA buttons
 AND #%00100000 ; only look at bit 0
  BEQ ReadUpDone
 
 
 
 
  LDA buttons
  AND #%00010000
 
   
 
  LDA gamestate
  CLC
  ADC #$01
  STA gamestate
 
ReadUpDone:
; run normal game engine code here
 ; reading from controllers, etc
 
 
 
  RTI              ; return from interrupt
 
 
 
 

DrawNewColumn:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$20          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  JSR levelselect
 

DrawColumn:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E         ; copy 30 bytes
  LDY #$1E
DrawColumnLoop:
  LDA [sourceLow], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop

 


 
DrawNewColumn2:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow2    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$28          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28 changes what loads the name table in the bottem name table in
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber2  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow2
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh2
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

DrawColumn2:
  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E              ; copy 30 bytes
  LDY #$1E
DrawColumnLoop2:
  LDA [sourceLow2], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop2

 

 
  RTS
 
 

 
 
DrawNewAttributes:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(attribData)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(attribData)
  STA sourceHigh

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone
 
  LDA columnLow         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow
  JMP DrawNewAttributesLoop
DrawNewAttributesLoopDone:

  RTS

DrawNewAttributes2:
  LDA nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$23          ; add high byte of attribute base address ($23C0)
  STA columnHigh    ; now address = $23 or $27 for nametable 0 or 1
 
  LDA scroll
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  CLC
  ADC #$C0
  STA columnLow     ; attribute base + scroll / 32

  LDA columnNumber  ; (column number / 4) * 8 = column data offset
  AND #%11111100
  ASL A
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

  LDY #$00
  LDA $2002             ; read PPU status to reset the high/low latch
DrawNewAttributesLoop2
  LDA columnHigh2
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDA [sourceLow2], y    ; copy new attribute byte
  STA $2007
 
  INY
  CPY #$08              ; copy 8 attribute bytes
  BEQ DrawNewAttributesLoopDone2
 
  LDA columnLow2         ; next attribute byte is at address + 8
  CLC
  ADC #$08
  STA columnLow2
  JMP DrawNewAttributesLoop2
DrawNewAttributesLoopDone2:


 


  rts
 
levelselect:

  LDA gamestate+1
  CMP #$00
  BEQ l00
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(columnDatay)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(columnDatay)
  STA sourceHigh
 
  RTS
l00:

  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #LOW(columnData)
  STA sourceLow
  LDA sourceHigh
  ADC #HIGH(columnData)
  STA sourceHigh
 
  RTS
 
Scrollcheck:
 
 
  LDA columnNumber
  CMP #$00
  BCC Neve
 
Sc:
 
  LDA scroll+2
  CMP #$20
  BEQ Endt
 
 
  RTS
 
Neve:

  LDA #$FF
  STA columnNumber
 
Endt:
  LDA columnNumber
  CLC
 
  ADC #$20
  STA columnNumber
 
  LDA #$00
  STA scroll+2 
 
 
  RTS
 
 
  RTS
 
;;;;;;;;;;;;;; 

  JMP BulletM




BulletM:
  CLC
  ADC #$02
  RTS

 


 
  Updating:

 
 


 
 
  LDA Frame
  CMP #$3C
  BCS AniFrame
 
  LDA #$00
  STA Frame
 
 
 
  LDA Timer1+3
  CMP #$00
  BEQ No
 
  LDA #$00
  STA Timer1+3
 
  JMP FS2
 
No:
 
  LDA #$01
  STA Timer1+3
 
FS2:

 
  LDA Timer1+11
  CMP #$03
  BEQ No2
 
  LDA #$01
  STA Timer1+10
 
  JMP FSl
 
No2:
 
  LDA #$01
  STA Timer1+3
 
 
 
  JMP FSl
 

 

 
FSl:
 
 
  LDA paletteswap+17
  CLC
  ADC #$01
  STA paletteswap+17
 
  LDA paletteswap
  CMP #$1D
  BCS Flu
 
  JMP Fly
 
 
Flu:
 
  LDA #$10
  STA paletteswap

Fly:
 

 
  LDA JumpState
  CMP #$02
  BCS AniFrame
 
AniFrame:

 
 
  LDA Srt
  STA $0211
  CLC
  ADC #$01
  STA $0215
 
  LDA Srt+1
  STA $0209
 
  LDA Srt+2
  STA $020D
 
  LDA JumpState
  STA $0219
 
  LDA JumpState+1
  STA $021B
 
  LDA Timer1+1
  STA $021A
 
 
 
Vertical:

 
 
 
  LDA player+1
  STA $0200
 
  LDA player+1
  STA $0204

  LDA player+1
  CLC
  ADC #$08  ; A = A - 1
  STA $0208

 LDA player+1
  CLC
  ADC #$08  ;     ; A = A - 1
  STA $020C

  LDA player+1
  CLC
  ADC #$0F  ; A = A - 1
  STA $0210

  LDA player+1
  CLC
  ADC #$0F  ;     ; A = A - 1
  STA $0214

Direction:
  LDA pdirection
  CMP #$01
  BCS Right
 
  LDA #$00
  STA pdirection+1
 
  LDA #$00
  STA pdirection+3
 
  LDA #$08
  STA pdirection+2
 
  BCC DDIR
 
Right:

  LDA #$08
  STA pdirection+1
 
  LDA #$40
  STA pdirection+3
 
  LDA #$00
  STA pdirection+2
 
DDIR:
 
  LDA pdirection+3
  STA $0202
  STA $0206
  STA $020A
  STA $020E
  STA $0212
  STA $0216
 
  LDA player
  CLC
  ADC #$04
  STA $0203
 
 

  LDA player
  CLC
  ADC pdirection+1 ; A = A - 1
  STA $020B

 LDA player
  CLC
  ADC pdirection+2  ;     ; A = A - 1
  STA $020F

  LDA player
  CLC
  ADC pdirection+1  ; A = A - 1
  STA $0213

  LDA player
  CLC
  ADC pdirection+2  ;     ; A = A - 1
  STA $0217
 
Gravity:

 

 
  LDA #GROUND
  CLC
  ADC #$01
  STA feet
 
  LDA player+1
  CLC
  ADC #$08
  STA grounded
   
 
 
 
   
 
  LDA grounded
  CMP #GROUND
  BEQ Fl
 
  JMP NP1
 
AnimationP3:
  JMP AnimationP1
 
Fl:
 
  LDA JumpState
  CMP #$01
  BCC AnimationP3
 
  LDA JumpState
  CMP #$01
  BEQ Jump
 
 
  LDA JumpState
  CMP #$01
  BEQ Jump
 
  LDA JumpState
  CMP #$02
  BEQ Delay
 
 
  LDA JumpState
  CMP #$03
  BEQ FP1
 
NP1:
 
  LDA JumpState+2
  CMP #$01
  BEQ Fl
 
  LDA #$03
  STA JumpState
 
  JMP Fl
 

Jump:

 


  LDA #$01
  STA JumpState+2
 
  LDA #$00
  STA gravity
 
 
  LDA #$01
  STA jheight
 
 
 
  LDA player+1
  CMP #$80
  BEQ Pa2
 
  JMP Can
 
Pa2:
 
  LDA scroll+1
  CMP #$FF
  BEQ Can
 
  LDA scroll+1
  CMP #$00
  BEQ Can
 
  LDA scrolly
  SEC
  SBC jheight
  STA scrolly
 
Can:
 
  LDA player+1
  SEC
  SBC jheight
  STA player+1
 
  LDA JumpState+1
  CLC
  ADC #$01
  STA JumpState+1
 
  LDA JumpState+1
  CMP #$18
  BCC AnimationP1
 
  LDA #$02
  STA JumpState
 
  LDA #$00
  STA JumpState+1
 
  LDA #$00
  STA JumpState+1
 
  JMP AnimationP1
 
FDP1:
  JMP FallDone

AnimationP1:
 
  JMP Animation

  FP1:
  JMP Fall
 


 
Delay:

 
  LDA #$00
  STA gravity
 
  LDA player+1
  SEC
  SBC jheight
  STA player+1
 
 
  LDA #$01
  STA jheight
 
 
  LDA JumpState+1
  CLC
  ADC #$01
  STA JumpState+1
 
 
  LDA JumpState+1
  CMP #$1E
  BCS P2
 
  LDA Timer1+3
  STA jheight
 
  JMP AnimationP1
 
P2:
 
  LDA JumpState+1
  CMP #$25
  BCS P3
 
  LDA #$00
  STA jheight
 
 
  JMP AnimationP1
 
AnimationP2:
  BCC AnimationP1
 
P3:
 
 
  LDA #$01
  STA gravity
 
  LDA #$01
  STA gravity
 
  LDA #$00
  STA jheight
 
  LDA JumpState+1
  CMP #$2A
  BCS P4
 
  LDA #$01
  STA gravity
 
  LDA #$01
  STA gravity
 
  JMP AnimationP1
 
P4:
 
 
  LDA #$00
  STA JumpState+1
 
  LDA #$03
  STA JumpState
 
 
  JMP AnimationP1
 

 
Fall:
 
  LDA grounded
  CMP feet
  BCS FDP1
 
  LDA #$00
  STA jheight
 
  LDA #$01
  STA gravity
 
  LDA player+1
  CLC
  ADC gravity
  STA player+1
 
  LDA JumpState+1
  CMP #$15
  BCS MV
 
  LDA JumpState+1
  CLC
  ADC #$01
  STA JumpState+1
 
  BCC AnimationP2
 
MV:
 
  LDA #$02
  STA gravity
 
  JMP AnimationP2
 
 

 

 

 
FallDone:

  LDA #$01
  STA JumpState+2
 
 
  LDA #$00
  STA gravity
 
  LDA #$00
  STA JumpState
 
  LDA #$00
  STA JumpState+1
 
  BCC AnimationP2
 
 
FireJump:
 
 
 
Animation:
 
  LDA JumpState
  CMP #$01
  BEQ JAniP
 
  LDA JumpState
  CMP #$02
  BEQ DAniP
 
  LDA JumpState
  CMP #$03
  BEQ FAniP
 
  LDA T
  CMP #$01
  BCC  Rss
 
  LDA Timer1
  CMP #$0F
  BCS  ResP2
 
  LDA Timer1
  CLC
  ADC #$01
  STA Timer1
 
  BCC SAni
 
 
ResP1:
 BCC Res
 
ResP2:
 BCS Res
 
 
Rss:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$06
  STA Srt
 
  LDA #$02
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
  BCC DoneP1
 
 
Res:
 
  LDA #$00
  STA Timer1
 
  LDA Ant
  CLC
  ADC #$01
  STA Ant
  BCC DoneP1
 
Rse:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  BCC DoneP1
 
JAniP:
 
  JMP JAni
  RTS
 
 
FAniP:
 
  JMP FAni
  RTS
 
DAniP:
 
  JMP DAni


  RTS

SAni:

 LDA JumpState
 CMP #$01
 BEQ JAni
 
 
 
 
FrameA1:
  LDA Ant
  CMP #$01
  BEQ FA2
  LDA #$0C
  STA Srt
 
  LDA #$04
  STA Srt+1
 
  LDA #$10
  STA Srt+2
 
  BCC DoneP1
 

 
FA2:
 
  LDA Ant
  CMP #$02
  BEQ FA3
  LDA #$0A
  STA Srt
 
  LDA #$02
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
  BCC DoneP1

FA3:
 
  LDA Ant
  CMP #$03
  BEQ FA4
  LDA #$0C
  STA Srt
 
  LDA #$0E
  STA Srt+1
 
  LDA #$0F
  STA Srt+2
 
 
  BCC DoneP1
 
RsP1:
  BCC Done
 
  DoneP1:
  BCC Done
 

 
  FA4:
 
  LDA Ant
  CMP #$04
  BEQ Rse
  LDA #$0A
  STA Srt
 
  LDA #$02
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
  BCC DoneP1
 
  LDA Ant
  CMP #$03
  BCS  RsP1
 




JAni:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$08
  STA Srt
 
  LDA #$04
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
 
 
  JMP Done
 
DAni:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$25
  STA Srt
 
  LDA #$23
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
 
 
  JMP Done
 
FAni:
 
  LDA #$00
  STA Ant
  LDA #$00
  STA Timer1
 
  LDA #$0C
  STA Srt
 
  LDA #$24
  STA Srt+1
 
  LDA #$03
  STA Srt+2
 
 
 
  JMP Done

Done:

 

ReadController1:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016
  LDX #$08
ReadController1Loop:
  LDA $4016
  LSR A            ; bit0 -> Carry
  ROL buttons     ; bit0 <- Carry
  DEX
  BNE ReadController1Loop
 
  RTS
 
ReadController2:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016
  LDX #$08
ReadController2Loop:
  LDA $4017
  LSR buttonslay            ; bit0 -> Carry
  ROL buttons     ; bit0 <- Carry
  DEX
  BNE ReadController2Loop
 
  RTS
 

 



 
  RTS

LoadPalettes2:


  LDA #%00000000        ; set to increment +32 mode
  STA $2000
 
 
  LDA $2002             ; read PPU status to reset the high/low latch
 
 
  LDA #$00
  STA Timer1+5
  STA Timer1+6
 
  LDX #$00
 
LP2:
 
   
 
  LDA #$3F
  STA $2006
  LDA Timer1+6
  STA $2006
 
  LDA paletteswap , x
  STA $2007
   
 
 
 
  INX
 
  INC Timer1+5
 
  INC Timer1+6
 
  LDA Timer1+5
  CMP #$20
  BEQ Fin
 
 
  JMP LP2
 
Fin:


  LDA #%00000100        ; set to increment +32 mode
  STA $2000
 
  RTS
 
   

 
 
 
 
 
 


 
 
 
;;;;;;;;;;;;;; 
 
 
 
  .bank 1
  .org $E000
palette:
  .db $02,$11,$01,$0F,$02, $04,$36,$37,$02,$39,$3A,$3B,$02,$16,$05,$0f
  .db $02,$16,$20,$38,$01,$0F,$07,$37,$02,$1C,$15,$14,$02,$0F,$07,$37
 
palette3:
  .db $02,$11,$01,$0F,$02, $04,$36,$37,$02,$39,$3A,$3B,$02,$16,$05,$0f
  .db $02,$16,$20,$38,$01,$0F,$07,$37,$02,$1C,$15,$14,$02,$0F,$07,$37
 
Playersprites:
   ; Player
   ;vert tile attr horiz
  .db $80, $00, $1C, $80   ;sprite 0
  .db $88, $02, $1C, $80   ;sprite 2
  .db $88, $03, $00, $88   ;sprite 3
  .db $88, $03, $00, $88   ;sprite 3
  .db $88, $03, $00, $88   ;sprite 3
  .db $8F, $04, $00, $80   ;sprite 3
 
 
;Bullets
Bullets:
  .db $8F, $1F, $04, $88 
  .db $8F, $1F, $04, $88 
  .db $8F, $1F, $04, $88 
  .db $8F, $FF, $04, $88 
 

Esprites:
  .db $10, $2F, $04, $88 
  .db $FF, $2F, $04, $FF 
  .db $8F, $1F, $04, $88 
  .db $8F, $FF, $04, $88 
 
  ;sprite 3
 
columnData:
 
 
 
 
  .incbin "KitsuneTaleslevel.bin"
 
 
 
columnDatay:
  .incbin "KitsuneTaleslevel2.bin"

attribData:
  .incbin "KitsuneTalesattrib.bin"
 
attribDatay:
  .incbin "KitsuneTalesattrib2.bin"
 
 

 
 
 
  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
 
 
;;;;;;;;;;;;;; 
 
 
  .bank 2
  .org $0000
  .incbin "KitsuneTalesShiroAkai.chr"
  ;;;;;;;;;;;;;;;;;;;;
  .bank 3
  .org $A000
  .incbin "Kitsunetales.chr"
 
 ;;;;;;;;;;;;;;;;;;;
 
  .bank 4
  .org $E000
 

What this is doing so far is that you ave a character running around with 5 8x8 sprites attached to it.
You can jump, the pallete stack $3F11 should change constantly, The nametables $20 and $28 should be both filled with a screen worth of info if a full level is loaded ala SMB3, Finally, paletteswap is the palette swapping variable.
GAME : Kitsune Tales
Re: Pallete affects scroll value
by on (#200614)
I see you moved out some of the logic from the beginning of the NMI, not everything though, the INC Scroll and the NTSwapCheck stuff are also logic and should be moved down after graphic updates. But now you have much more vblank time, do you still have the same problem?

I saw some other weird things. You clear RAM (at "clrmem") except page 3 that you fill with $FE:
Code:
  ;...
  LDA #$FE
  STA $0300, x
  ;...

You probably meant to fill page 2 with $FE to avoid stray sprites at boot since you are using that page as your OAM buffer for OAM-DMA.

And you only read bit 0 of $4016/$4017 in your controller reading routine so expansion port controllers doesn't work. You should read bit 1 as well unless it's a 4-player game.

Also I see you are doing the All-in-NMI approach. That's fine (Super Mario Bros is doing it that way) but it has its limits, and having logic in the main loop (the loop at "Forever" in your code) makes things more clear I think.
Re: Pallete affects scroll value
by on (#200615)
1. Yes, But listening to you des make a difference and that's nice. Wait I moved more logic around and It made a difference.
2. I Don't want the All nmi approach. I want some of the rendering to go Outside Like text, boss AI and other stuff. I heard that It boggles down speed if your not careful.
3. It's a one player game. However, If I get to demaking smash bros., I'll need that info
4. I found an article on stacks pha and pla. I just need to figure out where my buffer's going to go.
5. that was on the nerdy nights tutorial.
6. The scroll is only affected when it loads a section of the attibutes and the back ground.
7. I feel like I went too far off talking about stacks and what not. Should I continue?
Re: Pallete affects scroll value
by on (#200623)
If you are still having glitches, you're doing too much at once. One quick fix, would be to do the attribute table writes a frame early. It would look something like this...

NewAttribCheck:
LDA scroll
CLC ;!
ADC #1. ;!
AND #%00011111 ; check for multiple of 32
BNE NewAttribCheckDone ; if low 5 bits = 0, time to write new attribute bytes
jsr DrawNewAttributes

It may need more than just this, to make sure you write to the correct Nametable.
Re: Pallete affects scroll value
by on (#200675)
IMAGICA wrote:
2. I Don't want the All nmi approach. I want some of the rendering to go Outside Like text, boss AI and other stuff. I heard that It boggles down speed if your not careful.

Then just move out all your logic from the NMI and put it in your forever loop. Only keep the graphic updates (OAM, VRAM, $2000, $2001 and $2005 writes) in the NMI.

IMAGICA wrote:
3. It's a one player game. However, If I get to demaking smash bros., I'll need that info

You misunderstand me. If it's a one player game, you need to read both bit 0 and bit 1 of $4016 to your controller 1 data so that people can use both standard controllers and Famicom expansion port controllers. Nerdy Nights doesn't teach this but it's good practice to do it. Else people might not be able to use their arcade sticks and other controllers with your game.

IMAGICA wrote:
4. I found an article on stacks pha and pla. I just need to figure out where my buffer's going to go.

Your buffers goes into RAM wherever there is space. You are already buffering OAM and scroll in RAM. I like to keep my OAM buffer on RAM page 2 ($0200~$02FF), BG and palette buffers in page 3, and scroll and $2000/$2001 buffers in the zero page. The BG buffer can't be too big (there's not enough vblank time to draw the whole nametable), so you could also keep BG and palette buffers at the beginning of page 1. The stack starts in the other end of page 1 so unless you use a lot of stack there's no risk they will collide.
Re: Pallete affects scroll value
by on (#200767)
dougeff : Sorry, writing that slows dow the game. I need to learn buffering first
Pokun: What's bit one and how do you get it?
Re: Pallete affects scroll value
by on (#200783)
Bits in a binary number are traditionally numbered by their place value from right to left.

  • %00000001: Ones place, 1 = 2^0, bit 0
  • %00000010: Twos place, 2 = 2^1, bit 1
  • %00000100: Fours place, 4 = 2^2, bit 2
  • %00001000: Eights place, 8 = 2^3, bit 3
  • %00010000: Sixteens place, 16 = 2^4, bit 4
  • %00100000: Thirty-twos place, 32 = 2^5, bit 5
  • %01000000: Sixty-fours place, 64 = 2^6, bit 6
  • %10000000: One-hundred-twenty-eights place, 128 = 2^7, bit 7
Re: Pallete affects scroll value
by on (#200837)
Yes and if it's a one player game you read bit 0 and bit 1 of $4016 as controller 1 data so that either standard or expansion controller can be used. If it's a two player game you also read bit 0 and bit 1 of $4017 as controller 2 data. This is what (most) commercial games do.
Only if you have a three or four player game you would treat bit 0 of $4016 and $4017 as separate data (as controller 1 and 2) from bit 1 (as controller 3 and 4). In that case you would also want to support the four score.

IMAGICA wrote:
I need to learn buffering first

The Nerdy Nights sound tutorial actually has a (graphic) buffering system that is worth studying.
Re: Pallete affects scroll value
by on (#201432)
Can you confirm if I'm reading bit 1?
Code:
 LDA #$01
  STA $4016
  LDA #$01
  STA $4016
  LDX #$08
Re: Pallete affects scroll value
by on (#201442)
Not there. There you are writing to the $4016 output port, which is used by the controller as a command that it's time to send its current button data to the NES. It's called a latch or strobe for the controllers, and it gets you all controllers including the expansion port controllers.


Here is where you don't read bit 1:
Code:
  LDX #$08
ReadController1Loop:
  LDA $4016
  LSR A            ; bit0 -> Carry
  ROL buttons     ; bit0 <- Carry
  DEX
  BNE ReadController1Loop
 
  RTS

You shift bit 0 of $4016 into Carry (using LSR) and then rotate it out of Carry and into the RAM register "buttons" (using ROL). But you never touch bit 1 of $4016.

A simple way is to just add another set of LSR and ROL to get bit 1 into a temporary variable. Then you merge the two variables using OR.
Code:
  LDX #$08
ReadController1Loop:
  LDA $4016            ;get button data from bit 0 (con I) and bit 1 (con III)
  LSR A                ;shift button data from bit 0 into carry
  ROL buttons          ;rotate carry into a RAM register (con I buttons)
  LSR A                ;shift button data from bit 1 into carry
  ROL temp             ;rotate carry into a RAM register (con III buttons)
  DEX
  BNE ReadController1Loop

MergeControllers:
  LDA temp
  ORA buttons            ;OR con III with con I to merge them
  STA buttons

  RTS

And if your game is using two controllers you just repeat this code but use $4017 instead to get controller II and IV, and then merge them with each other the same way.



Edit: The easiest way to test if expansion port controllers (AKA controller III and IV) are working, is to test the game in an emulator like FCEUX and enable "Famicom 4-player Adapter" or similar. Then you just enable controller III in the emulator and see if it works with your game the same as controller I.
Re: Pallete affects scroll value
by on (#201448)
Thanks by the way what is the advantage of 8x16 sprites are? I willing to remake my sprites if it has advantages I need.
Re: Pallete affects scroll value
by on (#201454)
IMAGICA wrote:
Thanks by the way what is the advantage of 8x16 sprites are? I willing to remake my sprites if it has advantages I need.

We had a recent thread on that topic:
https://forums.nesdev.com/viewtopic.php?f=2&t=16235

The advantage is really just that they're bigger. You can cover more screen with them, and use all 8K of the CHR tables rather than just one 4K side.

Conversely, the disadvantage is also that they're bigger. You'll end up with more wasted space at edges, and probably more overlap problems (i.e. 8 sprites per scanline issues).
Re: Pallete affects scroll value
by on (#202893)
I'm Still here. I'm now fixing the vblank issue of the game.
I'm also goin to post the code for anyone to find pout the v blank issue that Pokun gave the answer to.
Pokun wrote:
IMAGICA wrote:
2. I Don't want the All nmi approach. I want some of the rendering to go Outside Like text, boss AI and other stuff. I heard that It boggles down speed if your not careful.

Then just move out all your logic from the NMI and put it in your forever loop. Only keep the graphic updates (OAM, VRAM, $2000, $2001 and $2005 writes) in the NMI.

IMAGICA wrote:
3. It's a one player game. However, If I get to demaking smash bros., I'll need that info

You misunderstand me. If it's a one player game, you need to read both bit 0 and bit 1 of $4016 to your controller 1 data so that people can use both standard controllers and Famicom expansion port controllers. Nerdy Nights doesn't teach this but it's good practice to do it. Else people might not be able to use their arcade sticks and other controllers with your game.

IMAGICA wrote:
4. I found an article on stacks pha and pla. I just need to figure out where my buffer's going to go.

Your buffers goes into RAM wherever there is space. You are already buffering OAM and scroll in RAM. I like to keep my OAM buffer on RAM page 2 ($0200~$02FF), BG and palette buffers in page 3, and scroll and $2000/$2001 buffers in the zero page. The BG buffer can't be too big (there's not enough vblank time to draw the whole nametable), so you could also keep BG and palette buffers at the beginning of page 1. The stack starts in the other end of page 1 so unless you use a lot of stack there's no risk they will collide.
Re: Pallete affects scroll value
by on (#202908)
The https://wiki.nesdev.com/w/index.php/The_frame_and_NMIs explains how you can structure your code to keep graphic updates and game logic separate.

A few problems:

Code:
  lda #%00000001
  sta $4017 ;enable Square 1

I guess you meant $4015 here, that's where you enable/diable APU sound channels.

Code:
clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0200, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem

I guess you meant to initialize $0200 to $FF, not $0300, since you are using $0200 as OAM buffer later in your code. You should do it like this:
Code:
clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0300, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0200, x
  INX
  BNE clrmem

This makes sure all sprites are off screen at boot, hiding them.


Code:
Forever:

  JMP Forever     ;jump back to Forever, infinite loop

Here is your main loop, here you can put all logic (except sound which is better off in the NMI to avoid sound lag).

Mine look something like this:
Code:
main:
  jsr con_read       ;read controllers
  jsr logic          ;state machine with all game logic, like: input handlers, moving objects, collisions gravity etc

  lda #$01
  sta draw_flag           ;allow NMI to draw, prevents incomplete buffering
nmi_wait:
  lda nmi_end_flag
  beq nmi_wait            ;wait for NMI to finish, this limits logic to a fixed frame rate
  lda #$00
  sta nmi_end_flag        ;clear NMI completion flag
  jmp main

At the end of the main loop I wait for an NMI to finish. This makes sure there is only one NMI (graphic update) per main loop (game logic). Inside the NMI I only update graphics if the draw flag is set, otherwise I skip it. This prevents the NMI from drawing a frame if the main loop hasn't finished in time for the vblank. Also at the end of the NMI I set the NMI end flag so the main loop knows when it's time to start the next iteration.

In your NMI you first push A, X and Y to the stack so they don't mess with your logic, should an NMI happen in the middle of it. Then check for the draw flag, and skip updates if it's clear, then you fires off your OAM DMA (writing 0 to $2003 and $02 to $4014) to update sprites. After that you should do all your nametable and palette updates ($2006 and $2007) and finally scroll ($2005) and any PPU setting changes ($2000 and $2001).

After that you can do sound and anything else that you want to happen constantly at 60 Hz (or 50 Hz if PAL) without lag, but doesn't need to be in vblank (because vblank time might be up before your NMI handler has finished, that's why we put graphic updates first in the NMI).
And finally last thing before the RTI you have to pull A, X and Y from the stack again (in reverse order from that you pushed them in).

Just ask if there's something not clear enough.
Re: Pallete affects scroll value
by on (#203731)
Pokun wrote:
Code:
main:
  jsr con_read       ;read controllers
  jsr logic          ;state machine with all game logic, like: input handlers, moving objects, collisions gravity etc

  lda #$01
  sta draw_flag           ;allow NMI to draw, prevents incomplete buffering
nmi_wait:
  lda nmi_end_flag
  beq nmi_wait            ;wait for NMI to finish, this limits logic to a fixed frame rate
  lda #$00
  sta nmi_end_flag        ;clear NMI completion flag
  jmp main


how would
Code:
 lda nmi_end_flag
  beq nmi_wait           

work in this function?

second if I were to modify the mirroring at the end, woulden't I get an error?
Heard that's only possible with mmc3.
Re: Pallete affects scroll value
by on (#203736)
The NMI handler interrupts the loop and sets the flag to a nonzero value.
Re: Pallete affects scroll value
by on (#203743)
Quote:
if I were to modify the mirroring at the end, woulden't I get an error?
Heard that's only possible with mmc3.


PPU Mirroring is hardwired into the PCB (by soldering a spot). It can't be changed except by a special mapper (such as MMC3).

Perhaps there is some other kind of mirroring you are talking about? Many of the CPU RAM addresses are mirrors of other addresses, for example.
Re: Pallete affects scroll value
by on (#203919)
tepples wrote:
The NMI handler interrupts the loop and sets the flag to a nonzero value.

How would that happen?

My code is stuck.

I can't just expect it to do it.
what's the "special flag" stack I need to link to it?
Re: Pallete affects scroll value
by on (#203921)
If you look at the wiki page on PPU registers...

http://wiki.nesdev.com/w/index.php/PPU_registers

You will see, setting bit 7 on register $2000 will tell the PPU to generate an NMI signal at the end of every frame (at the start of vertical blanking).

With NMIs on, the code will automatically jump to the NMI code (wherever the NMI vector points to), and then once it sees an RTI, will return to the main code.

The NMI code is where you should update sprites, make changes to the background, and call the music subroutine.

Or, you could just flip a NMI_flag on, and immediately RTI. In this scenario, the main code would be looking for changes in the NMI_flag, before it does those things I mentioned (sprites, BG, music)

And read the controllers, maybe.

Edit - on a side note, NMIs are not affected by SEI and CLI, hence the "non maskable" in the name.
Re: Pallete affects scroll value
by on (#204802)
Here's something I've learned:
Never use a NMI that is used to render 8x8 sprites to render 8x16 sprites
Also don't mess with the vblank. I am learning x and y rendering values.


... how do you push x and y?
phx and phy?
Re: Pallete affects scroll value
by on (#204803)
PHY and PHX don't exist.

PHY = TYA PHA
PHX = TXA PHA

If you need to preserve A, first store A to a temporary variable...

STA temp
TYA
PHA
LDA temp
Re: Pallete affects scroll value
by on (#204853)
dougeff wrote:
PHY and PHX don't exist.

They do exist in the 65C02 and 65816, but not in the 6502, which is the core the NES uses.
Re: Pallete affects scroll value
by on (#205121)
dougeff wrote:
PHY and PHX don't exist.

PHY = TYA PHA
PHX = TXA PHA

If you need to preserve A, first store A to a temporary variable...

STA temp
TYA
PHA
LDA temp

preserve A?
What's tat supposed to do?
also rendering the game with 8x16 sprites stops my game from working.
Re: Pallete affects scroll value
by on (#205151)
"What's that supposed to do?"
....A:80 X:40
STA temp
....A:80 X:40 temp:80
TXA
....A:40 X:40 temp:80
PHA ;A (40) pushed to stack
LDA temp
....A:80 X:40

Switching to 8x16 sprites shouldn't break your game. Perhaps you misunderstand how 8x16 sprites are organized....or made some other change.

Can you describe how it's "not working", or post a ROM?
TYA
by on (#205214)
dougeff wrote:
"What's that supposed to do?"
....A:80 X:40
STA temp
....A:80 X:40 temp:80
TXA
....A:40 X:40 temp:80
PHA ;A (40) pushed to stack
LDA temp
....A:80 X:40

Switching to 8x16 sprites shouldn't break your game. Perhaps you misunderstand how 8x16 sprites are organized....or made some other change.

Can you describe how it's "not working", or post a ROM?

Now it's not broken.
PHA and graphics are my main concerns now.
So:
PHA as I understand has to be ordered in a certain way.
In the beginning of the NMI, You're supposed to put
Code:
TXA
PHA

TYA
PHA

PHA

in any order
At the end of rendering as I know has to be Backwards of the original PHA Trio.
Code:
PHA

TYA
PHA

TXA
PHA

Now this causes a really bizarre effects on the game. It jitters up and down for a few seconds before locking in a certain position. Now, I know that my game's working. It's just not moving or registering my inputs or can't move the character at all.
Is my PHA example working? If so, Implementing the temp storage to pha will be a breeze.
2nd:
I know now that my graphics need adjustments to a 16 by 16 character. I will be adjusting it to reduce workload on the NES.
Re: Pallete affects scroll value
by on (#205216)
No, you need to use PLA for the end trio.

And you need to use PHA first before TXA or TYA or else you overwrite the old value of A and can't get it back.

PHA pushes the value in A to the stack.
PLA pulls the last value on the stack and puts it in A.

If you never remove things you push to the stack, your program will very likely break anytime you return (rti or rts) because rti and rts use values from the stack. That's where they get where to return to.
Code:
NMI:
;Information for RTI to work properly is the last thing on the stack.
PHA;The value of A is the last thing on the stack.

TXA;We have overwritten the value of A with the value of X
;But that's okay, because the old value of A is safe on the stack
PHA;Now what was the value of X is the last thing on the stack.

TYA;We have overwritten what was the value of X/A with the value of Y
;But that's okay, because the old value of A and the old value of X are safe on the stack.
PHA;Now what was the value of Y is the last thing on the stack.

;A, X, and Y are now all safely on the stack

;NMI Code here

PLA;The last value on the stack is removed and put into A. (The value for Y in this case)
TAY;We copy that value from A back to Y where it was before the NMI started.
;Because of that PLA now what was the value for X is the last thing on the stack.

PLA;The last value on the stack is removed and put into A. (The value for X in this case)
TAX;We copy that value from A back to X where it was before the NMI started.
;Because of that PLA now what was the value for A is the last thing on the stack.

PLA;Now the value of A is what it was before the NMI started.
;Because of that PLA now the information needed for RTI to work properly is again the last thing on the stack.
;A, X, and Y are now all safely off the stack
RTI;We can safely return now.
Re: Pallete affects scroll value
by on (#205217)
Alright! GOT IT TO WORRK. now to the character moving
Re: Pallete affects scroll value
by on (#205220)
It's called the stack because the elements in it are stacked on top of each other. Naturally if you throw a bunch of things in a stack, the last thing you threw will be on top, and when retrieving the things one by one, they will be retrieved in reverse order from the order they where thrown in.

If you always pair every push with a pull before the next RTS or RTI you will never normally have to worry about a stack overflow happening.
Re: Pallete affects scroll value
by on (#205269)
To reassure, EVERYTIME RTS and ARI comes in, place the PLA Trio THERE?
Re: Pallete affects scroll value
by on (#205270)
Quote:
To reassure, EVERYTIME RTS and [RTI] comes in, place the PLA Trio THERE?


Don't worry about standard subroutines (JSR, RTS) needing to preserve A,X,Y values.

Do worry about NMI and IRQ interrupts needing to.
Re: Pallete affects scroll value
by on (#205273)
NICE
now my mainproblem is tht the code in the nmi isn't working.
Re: Pallete affects scroll value
by on (#205292)
The reason why you need to backup the registers on the stack in interrupt handlers is that interrupts can potentially interrupt your code at any time. If it would interrupt in the middle of a calculation like:
Code:
  LDA #$05
                          <----NMI happens here
  CLC
  ADC #$03   ;calculate 5+3
The 5+3 calculation will not work if the NMI clobbers A.

For normal subroutines you have full control of when they are supposed to happen so you don't need to backup the registers.
Re: Pallete affects scroll value
by on (#205299)
I am often "passing an argument" to a subroutine using A,X,Y registers. And subroutines often "return a value"...usually the A register (sometimes just the zero flag or the carry flag is set or reset).

For example, a subroutine that multiplies, might have the input as A and X, and return A = A * X.

So, the original value in A needs to be overwritten by the subroutine.
Re: Pallete affects scroll value
by on (#205312)
Me too, but if I need to preserve the registers I would just back them up on the stack or in temporary RAM registers before calling the subroutine or whatever that clobbers them, and retrieve them when I need them again.
Re: Pallete affects scroll value
by on (#205814)
In a nutshell it looks like this?
Code:
  PHA
  STA temp
  LDA temp
  TXA
  PHA
  STA temp
  LDA temp
  TYA
  pha
  LDA temp
Re: Pallete affects scroll value
by on (#205832)
No, it should look exactly like it was in my post.

Code:
NMI:

  PHA
  STA temp;You're storing a new value into temp. (A)
  LDA temp;You're loading the value you just stored from A back into A. Why? The value that's there just came from A.
  TXA;You are putting the value of X into A, so the above line effectively does nothing because you never used the result.
  PHA
  STA temp;You're storing a new value into temp. (A) This effectively makes the first store to temp above do nothing, because its value effectively wasn't used in between being written and being overwritten.
  LDA temp;You're loading the value you just stored from A back into A. Why? That value is already in A.
  TYA;You are putting the value of X into A, so the above line effectively does nothing.
  pha
  LDA temp;This line effectively does nothing
 

NewAttribCheck:
  LDA scroll;Because of this line.


You're loading the value of temp into A, but before it is used, you load the value of scroll into A.

For understanding: The value of A doesn't change after a store, so loading from the exact place you just stored after a load usually does nothing. (Unless you're relying on flag changes, and you are not here.)

Edit: Just as another warning, you should make sure the temp RAM for your NMI isn't used anywhere else. (It's not here, but still.) For a similar reason to why you need to push A, X and Y to the stack. If the NMI interrupts code that expects the temp RAM to be a certain value, and the NMI changes the temp RAM very bad things will probably happen.

You can safely read variables in your NMI, always be careful when something is written.

Another similar piece of code:
Code:
DLs:
  lda columnNumber
  SEC
  SBC  #$01             ; go to next column
  and #%11111111       ; only 256 columns of data, throw away top bit to wrap
  sta columnNumber
  JMP Con;This line effectively does nothing

Con:

You are jumping to Con, but the code could naturally travel there if that line wasn't there.

One of the problems is that you have several RTIs in your code. JSR Updating eventually ends up at some animation labels (FAni, etc) that jumps to done:
Code:
Done:

  lda #$00
  sta NMIB+2
 
 
 
 
 
  PLA
  TAY
 
  PLA
  TAX
 
 
  PLA
 
  rti

Which pulls values off the stack that weren't pushed there (that I can see), and also returns with RTI instead of RTS.
Code:
main:
  JSR updating
  jmp main

updating:
  ;code in between
rts

Anything you JSR to should end in RTS (unless you really know what you're doing.) That is currently not true, at least for updating. One path of updating is updating->aniFrame->Vertical->Direction->DDIR->Gravity->F1->Jump->Delay->AnimationP1->Animation->scrolling->Pa2->Continue->p2->FAniP->FAni->Done->RTI

(That path may not be 100% possible since I didn't learn enough about your game state to be sure what are possible values. Still, you probably get the idea.)

You have another RTI under ReadUpDone that maybe should be an RTS, but I didn't take the time to study how your code gets there. (Or if it gets there.) The reason it's suspicious is because it doesn't pull values from the stack, and the only interrupt start code you have does push.

No matter how complicated the code in between updating: and the RTS is, updating still must end in RTS (unless you really know what you're doing.) This is how you get back to the line beneath way back near the "main:" label. Anytime I create a new subroutine, I make a habit of typing its name, then the RTS underneath it, both before even adding the JSR to its name to my code. Then I write the code in between and will be safe. If I want to create another subroutine the subroutine I just created goes to, same process. label, rts, then jsr, then code under label.

I'd maybe recommend starting completely over rather than trying to band aid this code. It probably sounds scary, but I think with what you've learned you'll actually spend less time rewriting than you will chasing problems in this and you'll end up with better code as a result. I recommend writing code in smaller parts. It helps me read, but it also helps you read.

I had to do a lot of work to find out what happened to updating. It could look something like this:

Code:
main:
  jsr waitVblank
  jsr updating
  jmp main

waitVblank:
;Code to wait for the frame start here
  rts

updating:
  jsr readbuttons
  jsr updateplayer
  rts

readbuttons:
  ;code to read buttons
  rts

updateplayer:
  jsr updateplayerstate
  jsr updateplayeranimations
  rts

updateplayerstate:
  rts
updateplayeranimations:
  rts

Basically, the more code you have in between the start of a subroutine's label and the RTS, the more paths you have to follow to find out what it's really doing. Dividing things allows you to create code you can verify all paths of without even scrolling in your text editor. Things get way less dense when you know the problem is in the 40 line updateplayeranimations rather than somewhere in 400 line updating.
NMI Is frozen / Not fully working
by on (#205839)
May need another Thread: Ok, Doing that in mind, and I know it's way off topic. For This game play, Should the sprites be bigger because you'll be flying via mid air dashing, shooting projectiles and wall jumping? I may need more ram than MMC3 chip for ai and other stuff. Maybe I need to understand how to compress code and to do this NMI Stuff before this challenge.


Before I fix. Is there another way to manage jumping? Look at from Jump to Animation
Re: Pallete affects scroll value
by on (#205844)
I wouldn't worry too much yet about using up everything the MMC3 has available. The MMC3 can handle games like Super Mario Bros 3 and Kirby's Adventure, which have lots of enemies, graphics, and moves.
Re: NMI Is frozen / Not fully working
by on (#205846)
IMAGICA wrote:
[color=#FF0000]

Before I fix. Is there another way to manage jumping? Look at from Jump to Animation


I think you would benefit from testing out 6502 code and stepping through it, to see how it all works.

https://skilldrick.github.io/easy6502/

This is a nice online 6502 emulator. Try writing some small test code.


To answer your question, seems to be about program flow control. Right? When to JMP and when to JSR and when to branch? I'm not sure I understand your question.

EDIT - or do mean having a character jump? Like handling the animation and collision detection of a jump?
Re: Pallete affects scroll value
by on (#205848)
IMAGICA wrote:
May need another Thread: Ok, Doing that in mind, and I know it's way off topic. For This game play, Should the sprites be bigger because you'll be flying via mid air dashing, shooting projectiles and wall jumping? I may need more ram than MMC3 chip for ai and other stuff. Maybe I need to understand how to compress code and to do this NMI Stuff before this challenge.


Before I fix. Is there another way to manage jumping? Look at from Jump to Animation
I think you should focus on getting your core working if it isn't already. And by core I mean your main loop and NMI. If you start adding lots of extra stuff before everything works as intended it will just complicate things even further.

I doubt you will need to compress any code. Get something smaller working first, and do things one step at a time. That's how I do it anyway.
Re: Pallete affects scroll value
by on (#205860)
dougeff wrote:

EDIT - or do mean having a character jump? Like handling the animation and collision detection of a jump?

Character.
Re: Pallete affects scroll value
by on (#205865)
The basics behind platformer physics is to have horizontal and vertical speeds for each object, that you add to their coordinates every frame. When characters are stationary, both speeds are 0. Pressing left/right gradually decreases/increases the horizontal speed by the acceleration value. The vertical speed can be affected by gravity (when there's no ground below a character, increase its vertical speed by the gravity value), or by jumping. Jumping can be implemented by setting the vertical speed to a high negative number, which will cause the character to move up pretty fast, and then gravity will kick in and gradually modify the vertical speed back into a positive value, eventually causing it to fall back down.
Re: Pallete affects scroll value
by on (#205866)
You can comment your code to describe what it's doing. What does a 1 in JumpState+2 mean? Why are you comparing JumpState+1 to #$14? What does #$14 represent?

Is player+1 the Y position?

I don't really follow what it's doing, it needs more context.

It requires understanding of 16 bit math, but here's fixed jump height code:

Code:
;playerY is the player's Y pixel position
;playerYSub is the player's Y position in between pixels (fractional position. 1/256th of a pixel)

;playerYSpd is the player's pixel speed (pixels per frame)
;playerYSpdSub is the player's fractional pixel speed (1/256th of a pixel per frame)

;grounded: If the player is on the ground, this is non zero
   
GRAVITY = 8
JUMPSTRENGTH = -512
GROUNDPOSITION = 200

   lda grounded;If the player is in the air, we need to
   beq addgravity;add gravity
   
   ;If here, the player is grounded and can jump if they press A
   
   lda buttons;if the player did not press A
   bpl nojump;no jump happened
   
   ;If here, the player pressed A, and we should jump
   
   lda #low(JUMPSTRENGTH);Set the player's speed
   sta playerYSpdSub;to the jump strength
   
   lda #high(JUMPSTRENGTH)
   sta playerYSpd
   
   ;and make the player not grounded
   lda #0
   sta grounded
   
   
   jmp updateyposition
addgravity:
   lda #low(GRAVITY);add gravity to the player's speed
   clc
   adc playerYSpdSub
   sta playerYSpdSub
   
   lda #high(GRAVITY)
   adc playerYSpd
   sta playerYSpd
   
updateyposition:
   ;Add speed to position to update the position
   lda playerYSpdSub
   clc
   adc playerYSub
   sta playerYSub
   
   lda playerYSpd
   adc playerY
   sta playerY
   
   ;If the player is not below the ground
   cmp #GROUNDPOSITION
   bcc jumpdone;We're done
   ;Otherwise, we ground them
   lda #$FF
   sta grounded
   
   ;set their falling speed to zero
   lda #0
   sta playerYSpdSub
   sta playerYSpd
   
   ;Set their position to the ground
   lda #GROUNDPOSITION
   sta playerY
   
   lda #0;The ground is a pixel position
   sta playerYSub;so the fractional part is just zero

jumpdone:
nojump:


Here's what it looks like:
Image
Edit: Actually that's probably not quite what it should look like. What I hacked it into probably ran it twice per frame instead of once. Changing GRAVITY to 24 would probably get a similar enough result to the animation.
Re: Pallete affects scroll value
by on (#206499)
The background changed to it's 8x16 counterpart for some reason, looks freaky.
character's changed againmeaningless
reverted the pla and pha to the basicsno more STA/LDA temp for now
and now the second part of the jsr problems that Kasumi mentioned is beinfg worked on
Re: Pallete affects scroll value
by on (#206504)
I apologize, sincerely. Please don't take offense. This code is not good. It crashed almost immediately. Start over. Really. Blank slate. Start over. You need a stable loop before you add anything to it.

Fr .rs 1
Timer1 .rs 12
ANT .rs 4
T .rs 1
Srt .rs 6

What are these? I don't know. There's no comments, and the variable names are impossible to figure out.

NMI:

PHA
STA temp
TXA
PHA
TYA
pha

Why are you STA temp here? There's no other reference to temp.

...



RTS ?

no. The NMI routine ends in RTI. AFTER you do this stuff...

PLA
TAY
PLA
TAX
PLA
RTI




...

jsr Updating

but you have this subroutine end in...

PLA
TAY
PLA
TAX
PLA
rti

Where it should end in

RTS

This is almost certainly where it is crashing. Here or after the first NMI tries to RTS and it finds X and Y values rather than a return address.
Re: Pallete affects scroll value
by on (#206505)
Removed Updating until scrollCheck
there is only RTS in between
edit
Code:
Forever:
  INC NMIB+2
 
  lda #$01
  sta NMIB ;allow NMI to draw, prevents incomplete buffering
nmi_wait:
 
 
  lda NMIB+2
  BEQ nmi_wait
 
  lda #$00
  sta NMIB
 
  ;wait for NMI to finish, this limits logic to a fixed frame rate
main:
 
  jsr ReadController1 ;read controllers
  [ Read conrtollers1:
....
  RtS]  jsr Updating ;state machine with all game logic, like: input handlers, moving objects, collisions gravity etc
[updating:
...
Rts]
 

 
 
 
  jmp Forever

 
 
 
 
 
  JMP Forever     ;jump back to Forever, infinite loop
 
Re: Pallete affects scroll value
by on (#206506)
Just as a practice exercise, I recommend when you rewrite your code. Follow this constraint. No subroutine shall exceed 50 lines.

Then, your main routines will be just a series of subroutine calls.

JSR Read_Controllers
JSR Move_Hero
JSR Scrolling
JSR Move_Enemies
JSR Handle_Collisions

Etc.

Then, just before each subroutine, a detailed comment on what the subroutine does. If it passes any values, list what kind of value(s) it passes.

If a subroutine is longer than 50 lines, try to break it into smaller subroutines.

Every non-trivial variable should tell you what it does, just by its name.

y_scroll
x_scroll
hero_size
jump_height

And so forth.

In 6-12 months, when your code is 10,000 lines long, you will thank me.
Re: Pallete affects scroll value
by on (#206507)
Challenge....Subverted
loop isn't working at all
Re: Pallete affects scroll value
by on (#206514)
Listen to me 11 days ago, listen to dougeff. Please restart, write smaller pieces of code, don't only come to us when your code visibly doesn't work. You're clearly not understanding some of the things you're trying, and by the time it gets broken in a way you can see there is way too uncommented code for us to comb through in a reasonable amount of time.

Anytime you're not sure about something, you can just ask. Because anytime something appears to work, but you don't really understand why is a problem waiting to happen.
Re: Pallete affects scroll value
by on (#206995)
Where would the rti be?
Would it be after evey 50 lines or after all code before JMP Forever?
Re: Pallete affects scroll value
by on (#206998)
IMAGICA wrote:
Where would the rti be?
Would it be after evey 50 lines or after all code before JMP Forever?


In most of the games I programmed, there is 1 rti in the entire game code...

NMI:
inc nmi_flag
inc frame_count
IRQ:
rti

The IRQ handler being an empty routine that just returns.

My Ninja game has 2 RTIs in the entire game. One for NMI code (at the end of it) and one for the IRQ code (at the very end of it). It uses a MMC3 mapper generated IRQ (scanline counter) to do a mid-screen split scroll.
Re: Pallete affects scroll value
by on (#207028)
Double post... just making sure you understand.

As the 6502 executes code, it keeps track of the current address of code being executed, called program counter (PC).

JSR - "jump to subroutine", takes pushes the address-1 (2 bytes) of the next operation on to the stack, and replaces the PC with then JSR address, at which point it starts executing from the subroutine.

RTS "return from subroutine", it pops 2 bytes off the stack, and puts them into the PC, at which point it starts executing from the next line after the last JSR.

An interrupt (NMI or IRQ), will pushes three bytes onto the stack. First is the high byte of the return address, followed by the low byte, and finally the status byte from the P processor status register. Then it replaces the PC from the NMI (or IRQ) vector table at the end of the ROM, at which point it starts executing from the NMI (or IRQ) routines.

RTI -"return from interrupt" pops 3 bytes from the stack, first the processor status flags, then the return addresses, replacing the PC, at which point it will continue executing from wherever (could be anywhere) it was prior to the interrupt.

If you try to RTI before an interrupt happens, it will try to pop 3 bytes off, but not get a usable address, which would crash the game.

If you JSR, then RTI, it will push 2 bytes, but try to pop 3 bytes. It won't get the right address, since the first byte is the processor flags, and it will crash the game. (It's not even the same address pushed. JSR pushes the next line minus 1, and an interrupt pushes the next line exactly. I don't know why they engineered it that way, but it makes it doubly incompatibe).

Clear?
Re: Pallete affects scroll value
by on (#207809)
This is the list of It Red text shows what was deleted green shows what was added
forever:
JSR 2
RTS -2
NMI/ IRQ 3
RTI -3

JSR RC1 +2 2
RTS RC1 -2 0
JSR Player +2 2
RTS Player -2 0
RTI -3;crash
NMI +3 3
JSR DNA 2 5
RTS DNA -2 3
JSR DNC 2 5
JSR ls 2 7
RTS ls -2 5
RTS DNC -2 3
JSR SC 2 5
RTS SC -2 3
RTI -3 0
Goal 1: Get game 'running'; notes: thank you dougleff The chart above shows the info in practice.
Goal 2: Get game to stop stuttering; notes: Pokun has info about vblanking with forever.
Re: Pallete affects scroll value
by on (#207810)
The stack resides at $0100-$01FF. This is what happens when you press left in FCEUX:
Image
so you still have some type of stack issue.
Re: Pallete affects scroll value
by on (#207811)
Is there another thing I have to record to fixit because that's something new I've encountered.
Apart from before nmi Problems
delete the scroll stack if you want that effect again
Re: Pallete affects scroll value
by on (#207813)
GOT IT TO WORK

Main code:
Code:
LDA $01
  STA NMIB+1
 
  LDA NMIB+1
  cmp $00
  BCS waitforframe
 
  jsr ReadController1 ;read controllers
 

  jsr Player ;moves a sprite vertically across screen
 
waitforframe:
  lda NMIB+1
  beq waitforframe
 
 
  LDA $00
  STA NMIB+1
 
Re: Pallete affects scroll value
by on (#207814)
lda $00 is equivalent to lda speed in your program.
cmp $00 = cmp speed.

lda $01 is equivalent to lda temp.

lda $XX reads the value from RAM location $00XX and puts that into A. lda #$XX puts the actual value $XX into A.

The only reason this code works is because your program starts by setting all RAM to zero.
Re: Pallete affects scroll value
by on (#207815)
Is that a problem
if yes:
How can I fix?
Re: Pallete affects scroll value
by on (#207816)
Pokun wrote:
Code:
Forever:

  JMP Forever     ;jump back to Forever, infinite loop

Here is your main loop, here you can put all logic (except sound which is better off in the NMI to avoid sound lag).

Mine look something like this:
Code:
main:
  jsr con_read       ;read controllers
  jsr logic          ;state machine with all game logic, like: input handlers, moving objects, collisions gravity etc

  lda #$01
  sta draw_flag           ;allow NMI to draw, prevents incomplete buffering
nmi_wait:
  lda nmi_end_flag
  beq nmi_wait            ;wait for NMI to finish, this limits logic to a fixed frame rate
  lda #$00
  sta nmi_end_flag        ;clear NMI completion flag
  jmp main

.

This is what ive referenced
Re: Pallete affects scroll value
by on (#207817)
Quote:
This is what ive referenced

But you copied it incorrectly. You used lda $01, that code uses #$01 and they are very different.

First, for understanding. Here is some example code:
Code:
lda #$FF;A=#$FF
sta $00;$00 = A. A=#$FF. So $00 has the value #$FF inside.

lda $00;A=#$FF
lda #$00;A=#$00


If you want to load a number, precede it with # like so
lda #$00
If you want to load a value in ROM or RAM, don't. like so
lda $00
But usually you would never do with a number. You'd usually use named RAM like
lda speed
instead if you wanted that.

So look for places in your code where you forgot the '#' symbol. Here's one:
Code:
Player:
 
  INC $0200
  INC scroll
  LDA $00;You probably want lda #$00 here.
  STA scroll
 
  RTS
Re: Pallete affects scroll value
by on (#207819)
Alright. So that Sta temp from the PHA could be used to load it into that stack
BTW Code stop
P.S. How ca I yse this knowledge to fix vblanking
Re: Pallete affects scroll value
by on (#207822)
Code:
Forever:
 
  LDA NMIB+1
  cmp #$01
  BEQ waitforframe
 
  jsr ReadController1 ;read controllers
 

  jsr Player ;moves a sprite vertically across screen
  jsr Direction
  JSR AniFrame
 
  LDA #$01
  STA NMIB+1
 
waitforframe:
 
  lda NMIB+1
  Cmp #$01
  beq waitforframe
 
  LDA NMIB+1
  cmp #$01
  BEQ waitforframe
 
  LDA #$00
  STA NMIB+1
 
  jmp Forever

Got it... I think.....
Re: Pallete affects scroll value
by on (#207826)
You have a much harder problem. After the NMI happens, you have about 2270 "cycles" to safely write to parts of the PPU. A "cycle" is a bit like a measure of time. Each instruction takes a certain amount of time.

From NMI:
to
STA $4014

in your program takes 2427 cycles. You have to optimize your code for speed and that's... not an easy topic to cover. But to start with, here's two facts.
1. The NMI lets you know when a brief period of time starts that allows you to write to places like $2007 safely while the screen is being rendered.
2. In your "Forever" loop, you have quite a lot of time, but can't write to places like $2007 safely.

The solution: Do absolutely everything you can in your forever loop, short of actually writing to $2007.

Your NMI could look something like this:

Code:
NMI:
PHA
 
  TXA
  PHA
  TYA
  pha


lda #$20;Always write to one nametable for the example
sta $2006
lda #$00
sta $2006
LDA #%10110000
sta $2000;increment by one

ldy #0
nmiloop:
lda $0500,y;4 cycles
sta $2007;4 cycles
iny ;2 cycles
cpy #32;2 cycles
bne nmiloop;3 cycles taken


 LDA #$00
  STA $2003       
  LDA #$02
  STA $4014       ; sprite DMA from $0200


LDA #%10110000
ora nametablescroll
sta $2000

lda #$00;reset scroll to zero
sta $2005
sta $2005



INC NMIB+1

PLA
  TAY
  PLA
  TAX
  PLA
  RTI             ; return from interrupt

That copy loop could be made faster, but let's keep it simple for now.

This makes it so your NMI does very few things.
1. Pushes your registers (X, Y and A) to the stack. This is pretty much required.
2. Write the top row of nametable0's address to $2006
3. Reads 32 bytes from $0500-$051F and stores them to $2007.
So effectively, it copies 32 bytes from $0500 to the top row of the first nametable.
4. Sets your scroll to 0, 0.
5. increments NMIB+1 so your main loop stops waiting.
6. pulls your registers from the stack. (Also pretty much required.)

Since your NMI (in this example) is copying bytes from $0500-$051F, your next step is to ready that data in your forever loop. So code like DrawNewColumn would be run in the forever loop, but instead of storing to $2007, it'd store to $0500,y. And then when the next NMI happens, it will be read from $0500,y and written to $2007 when it's safe to do so.

This is a super simplified way to approach this, but that's the theory. Say you want to copy to a different address. No problem. Create two variables to store the address you want to write to in your forever loop, and then read that from RAM in your NMI. Say you don't want to draw a new row every frame. No problem. Create a variable that says whether your NMI should copy a new row. Set it in your Forever loop. Read it in your NMI and skip the $2007 writes if it says to. Say you want to copy new columns instead of rows. No problem. Create a new variable that specifies the type of copying to be done.

You want your NMI to be making as few decisions as possible because the time is very limited, so this approach (write to $0500 or elsewhere in RAM while you have a lot of time, then directly copy when you don't) is a good one.
Re: Pallete affects scroll value
by on (#208180)
Kasumi wrote:
You have a much harder problem. After the NMI happens, you have about 2270 "cycles" to safely write to parts of the PPU. A "cycle" is a bit like a measure of time. Each instruction takes a certain amount of time.

From NMI:
to
STA $4014

in your program takes 2427 cycles. You have to optimize your code for speed and that's... not an easy topic to cover. But to start with, here's two facts.
1. The NMI lets you know when a brief period of time starts that allows you to write to places like $2007 safely while the screen is being rendered.
2. In your "Forever" loop, you have quite a lot of time, but can't write to places like $2007 safely.

The solution: Do absolutely everything you can in your forever loop, short of actually writing to $2007.

Your NMI could look something like this:

Code:
NMI:
PHA
 
  TXA
  PHA
  TYA
  pha


lda #$20;Always write to one nametable for the example
sta $2006
lda #$00
sta $2006
LDA #%10110000
sta $2000;increment by one

ldy #0
nmiloop:
lda $0500,y;4 cycles
sta $2007;4 cycles
iny ;2 cycles
cpy #32;2 cycles
bne nmiloop;3 cycles taken


 LDA #$00
  STA $2003       
  LDA #$02
  STA $4014       ; sprite DMA from $0200


LDA #%10110000
ora nametablescroll
sta $2000

lda #$00;reset scroll to zero
sta $2005
sta $2005



INC NMIB+1

PLA
  TAY
  PLA
  TAX
  PLA
  RTI             ; return from interrupt

That copy loop could be made faster, but let's keep it simple for now.

This makes it so your NMI does very few things.
1. Pushes your registers (X, Y and A) to the stack. This is pretty much required.
2. Write the top row of nametable0's address to $2006
3. Reads 32 bytes from $0500-$051F and stores them to $2007.
So effectively, it copies 32 bytes from $0500 to the top row of the first nametable.
4. Sets your scroll to 0, 0.
5. increments NMIB+1 so your main loop stops waiting.
6. pulls your registers from the stack. (Also pretty much required.)

Since your NMI (in this example) is copying bytes from $0500-$051F, your next step is to ready that data in your forever loop. So code like DrawNewColumn would be run in the forever loop, but instead of storing to $2007, it'd store to $0500,y. And then when the next NMI happens, it will be read from $0500,y and written to $2007 when it's safe to do so.

This is a super simplified way to approach this, but that's the theory. Say you want to copy to a different address. No problem. Create two variables to store the address you want to write to in your forever loop, and then read that from RAM in your NMI. Say you don't want to draw a new row every frame. No problem. Create a variable that says whether your NMI should copy a new row. Set it in your Forever loop. Read it in your NMI and skip the $2007 writes if it says to. Say you want to copy new columns instead of rows. No problem. Create a new variable that specifies the type of copying to be done.

You want your NMI to be making as few decisions as possible because the time is very limited, so this approach (write to $0500 or elsewhere in RAM while you have a lot of time, then directly copy when you don't) is a good one.

SO if I'm reading this correctly, Put Drawcolems,Drawattributes into Forever and put this in the nmi?
Also when MMC5 is enabled, black screen is inevitvlble. Is bank switching needed
also is the back ground normal?
Re: Pallete affects scroll value
by on (#208191)
You can't only put Drawattributes/Drawcolumns into forever because they write to $2006/$2007. You have to modify them so they write to RAM instead. Your NMI must then read from this RAM and write that data to $2007 as fast as possible.

You last ROM used mapper 4, which is MMC3 not MMC5. Has something changed? I would not recommend switching mappers right now.

The background for your ROM only appeared normal in less accurate emulators, your last write to $2007 in your NMI cannot occur as late as it does.
Re: Pallete affects scroll value
by on (#208195)
No just wondering. mmc question
Also one more thing.
'For the background, does this have a bad effect on it?
Code:
DrawNewColumn:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  STA switchrender
  CLC
  ADC #$20          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh
 
  JSR levelselect
 

DrawColumn:
  LDA #%00100100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$0F     ; copy 30 bytes
  LDY #$1E
DrawColumnLoop:
 
  LDA [sourceLow], y
  STA $2007
 
 
  CLC
  ADC  #$01
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop
 

  LDA switchrender
  CLC
  ADC #$28
  STA columnHigh
 
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006 
  LDX #$0F   ; copy 30 bytes
 


 
 
 

DrawColumnLoopP2:
 
  LDA [sourceLow], y
  STA $2007
 
  CLC
  ADC  #$01
  STA $2007
  INY
  DEX
  BNE DrawColumnLoopP2

  RTS
Re: Pallete affects scroll value
by on (#208208)
I'm not sure I understand why those changes were made. You're writing the value from [sourcelow],y to $2007, then adding 1 that value and writing that to $2007. So for every byte in the address pointed to in sourcelow, you're writing two bytes. You're also not starting from zero. (LDY #$1E), which I'm not sure is correct. (Maybe you did that before? I forget)

But aside from that, your rom is smaller than it should be. (I probably should have mentioned this a while ago.) NESASM considers a bank to be 8KB always. The header for an NES rom considers PRG banks (code/data) to be 16KB and CHR banks (graphics) to be 8KB.

Your code starts like this:
Code:
.inesprg 1  ; 1x 16KB PRG code
.ineschr 4   ; 1x  8KB CHR data

16*1 (the size in KB of PRG banks)
+
4*8 (the size in KB of CHR banks)
=
48

48/8 (the size in KB of a bank to NESASM)
=
6

So you should have 6 .bank directives in your code. 2 for PRG, and 4 for chr. Your two for prg are correct.
Code:
.bank 2
  .org $0000
  .incbin "Electro_and_Shiro.chr"
  ;;;;;;;;;;;;;;;;;;;;
  .bank 3
  .org $0000;This might change how your rom behaved? But I don't think $A000 was right
  .incbin "Kitsunetales.chr"
 
 ;;;;;;;;;;;;;;;;;;;
 
  .bank 4
  .org $0000

 .bank 5
 .org $0000
Re: Pallete affects scroll value
by on (#208249)
Answer to first question:
This is so that I can double the screen size Ala SMB3 by using adjacent tiles to get a certain effect of doubling the screen size using one hex memory address, effectively filling both "screens" of the PPU. While my arrogance that has shown prominently during this wants to explain how I did it, I want to tell you what it was originally
Code:
DrawColumn:
  LDA #%00100100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E         ; copy 30 bytes
  LDY #$1E
DrawColumnLoop:
  LDA [sourceLow], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop

 


 
DrawNewColumn2:
  LDA scroll       ; calculate new column address using scroll register
  LSR A
  LSR A
  LSR A            ; shift right 3 times = divide by 8
  STA columnLow2    ; $00 to $1F, screen is 32 tiles wide

  LDA nametable     ; calculate new column address using current nametable
  EOR #$01          ; invert low bit, A = $00 or $01
  ASL A             ; shift up, A = $00 or $02
  ASL A             ; $00 or $04
  CLC
  ADC #$28          ; add high byte of nametable base address ($2000) can change to lower name table $2000 = ADC #$20 $2800 = ADC #$28 changes what loads the name table in the bottem name table in
  STA columnHigh    ; now address = $20 or $24 for nametable 0 or 1

  LDA columnNumber2  ; column number * 32 = column data offset
  ASL A
  ASL A
  ASL A
  ASL A
  ASL A             
  STA sourceLow2
  LDA columnNumber
  LSR A
  LSR A
  LSR A
  STA sourceHigh2
 
  LDA sourceLow       ; column data start + offset = address to load column data from
  CLC
  ADC #$04
  STA sourceLow2
  LDA sourceHigh
  ADC #$04
  STA sourceHigh2

DrawColumn2:
  LDA #%00100100        ; set to increment +32 mode
  STA $2000
 
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA columnHigh
  STA $2006             ; write the high byte of column address
  LDA columnLow
  STA $2006             ; write the low byte of column address
  LDX #$1E              ; copy 30 bytes
  LDY #$1E
DrawColumnLoop2:
  LDA [sourceLow2], y
  STA $2007
  INY
  DEX
  BNE DrawColumnLoop2

 
;;;;;;;;;;
scrollCheck:

 
  LDA player
  CLC
  ADC #$08 
  CMP #$80
  BEQ ReadController1
 
  LDA player
  CLC
  ADC #$08 
  CMP #$80
  BCC Rights
 
 
 
  LDA player
  SEC
  SBC #$01
  STA player
   
  LDA #$00
  STA sdir
 
  JMP ReadController1
 

 
  RTS
witch took too much memory from the hex by using the next screen data, halving the game's level data.
The new code like you said
Quote:
[writes] the value from [sourcelow],y to $2007, then adding 1 that value and writing that to $2007. So for every byte in the address pointed to in sourcelow, you're writing two bytes.
Whitch keeps the level long without compensating the length.

Answer to the second question:
The game isn't finished. When I learn Bank switching and r-a-m- -s-t-o-r-a-g-e(already done) , I'll get working on the other game elements. If there's problem with it, tell me please.
Re: Pallete affects scroll value
by on (#208252)
Yes, there is a problem. Your ROM claims to be 48KB in the header, but it's only 40KB, which makes some emulators reject it outright. Nestopia is one such emulator. VirtuaNES is another. Adding the bank directive as I've instructed will tell NESASM to add another CHR bank (8KB) to your file so that it will be the proper size.

One thing to note is that $2000 isn't written to before (or in) DrawNewAttributes in the NMI, so when $2007 is written to in DrawNewAttributes it is incrementing by whatever was last written to $2000.

Your game crashes when you press A because of this code:
Code:
LDA JumpState;If JumpState is >= 1
  CMP #$01
  BCS ReadADonep1;go to ReadADonep1
 
  LDA #$01;This makes JumpState equal to 1
  STA JumpState
ReadADonep1: 
 
  LDA JumpState;If JumpState is >= 1
  CMP #$01;Go to ReadADonep1
  BCS ReadADonep1;Because ReadADonep1 is directly above, this is an endless loop.
Re: Pallete affects scroll value
by on (#208450)
Trying to write to $0700 and every time I do, It resets to $FF
Code:
DrawColumnLoop:
 
  LDA [sourceLow], y
  STA $0700,y
  INY 
  DEX
  BNE DrawColumnLoop
 
 
  RTS
Re: Pallete affects scroll value
by on (#208495)
First: There is no ROM, nor a way to build the ROM, so I can't even see the problem you're currently talking about. Can you share the other files one needs to build the game, instead of just the .asm? "KitsuneTaleslevel.bin", "KitsuneTaleslevel2.bin", "KitsuneTalesattrib.bin", "KitsuneTalesattrib2.bin", "Electro_and_Shiro.chr" and "Kitsunetales.chr". This forum allows you to upload .zip files, so you can upload your project file as one file.

Edit:
Second: Please make the changes I suggested in my last post about CHR. I now see that you changed .ineschr to 3 instead of 4, but that... creates a different kind of problem. Potentially the problem you're describing.

The size of your CHR and PRG should be a power of two. If you multiply your .ineschr value by 8192 you'll get 24576 which is not a power of two. What I outlined as a fix was a way to avoid all of this kind of stuff. You want .ineschr 4, you want a .bank 5, and you want .org $0000 under each CHR .bank statement. (so .bank 3, .bank 4, and .bank 5 would want .org $0000 under them, instead of .org $A000 and $E000. .bank 2 is correct.) The last CHR banks can be empty, but they need to be there.

Third: Without building the ROM, that code looks like it'd do exactly what I said it'd do. That is, copy a single column from the address pointed to in sourceLow and sourceLow+1 to RAM (except at $0700+ rather than $0500+). So can you be more specific about the difference between what you are expecting to happen and what is actually happening?

Edit 2: Because it will help replicate exactly what you're seeing, what emulator are you using, and what version of that emulator? If testing on real hardware, what flash card/other type of cartridge? (Though I only own a powerpak and infiniteneslives MMC3 cart, so if it's not those then I can't see it exactly.)
Re: Pallete affects scroll value
by on (#208509)
Quote:
I want to program a MMC3 demake of smash bros, what's a vblank?


STOP and go read the basics immediately. Go read a decent tutorial (Nerdy Nights at a minimum, I'm sure people here have links to better reading material though) before trying to code complex stuff. You're not going anywhere if all you do is copy/paste code you barely understand even if we try our best to help you. Look at the complexity of a simple breakout game I've coded:

https://github.com/AleffCorrea/BrickBre ... lision.asm

Roughly 500 lines just for background and sprite collision detection... feel free to browse the rest of the files from my game. Don't be overwhelmed by it though, trust me when I say that if you stop what you're trying to do right now and direct your efforts towards learning the underlying concepts first you'll be doing code that is 10 times better than mine in no time.
Re: Pallete affects scroll value
by on (#208738)
Here
Re: Pallete affects scroll value
by on (#208739)
YOU
Re: Pallete affects scroll value
by on (#208754)
I got rid of the code under anim, and scrollCheck. It wasn't used.
I got rid of readjoy. It wasn't used.
I got rid of Loadp. It wasn't used.
I got rid of LoadPalettes2. It wasn't used.

I recommend getting rid of dead code like that, it makes for way less to sift through while looking for errors.

DrawNewColumn uses columnNumber to decide which column to draw (which address to put into sourceLow and sourceHigh). columnNumber gets incremented every frame, so most of the time it's loading from data totally beyond your level data. Since the byte that's used to pad unused space is $FF in NESASM, this is why mostly $FF gets copied. Why columnNumber gets incremented, I have no idea. It's hard for me to follow the current code. And I know how I'd find out what's wrong, exactly, but I genuinely think the time would be better spent helping you rewrite it. As I, and others, have recommended, I would rewrite this one small step at a time.

1. Write code that copies a single fixed column to RAM.
When that works (check the RAM with FCEUX's hex editor)
2. Write code that copies a single column to RAM, that you can change with the d-pad. (Say... pressing right picks the next column. Pressing left picks the previous column.)
When that works (check the RAM with FCEUX's hex editor)
3. Write code in your NMI that writes the values in the "column RAM" to $2007 fixed to one column's address.
When that works (you can just see it)
4. Write code in that sets an address for $2006 to a specific column, that is also changed with the d-pad.
When that works (check the RAM for the address for $2006 gets stored to)
5. Write code in the NMI that uses the address you set above to write to $2006 so the $2007 writes go to the right place.
When that works (you can just see the columns get written to the right place by using the d-pad)...
6. Write code that writes all columns one frame at a time without the use of the d-pad.
When that works...
7. Move the code in the NMI that writes to $2006 and $2007 to a subroutine and call it from the NMI.
When that works...
8. Disable rendering and use that subroutine in addition to your column to RAM code to write all columns in a single frame.
When that works...
9. When rendering is enabled, make it draw a new column when the screen is scrolled.
When that works...
etc.

I outline these steps to try to teach what making small testable parts is like. If you don't have a good guess of where a problem is when you're coding, you're probably writing too much before testing.

You didn't answer my question: What test setup (emulator/cartridge) are you using?

Edit: For the record I do see you are taking steps to writing small parts like this, but the reason your code is broken right now is actually stuff you wrote before. So I'm saying get rid of that stuff in addition to doing each small part.
Re: Pallete affects scroll value
by on (#208777)
Test Setup?:
Fceux first check value, see if my code is working, try to break code. Move on.

wanna see an example? press up and down on the dpad using the kitsune3 code . theres the test of rendering.
Ive Also learmned what vnblabnking is
Re: Pallete affects scroll value
by on (#208783)
I saw an example. I even told you what was wrong, just not specifically how to fix it. You're doing things to columnNumber for reasons I don't understand. If you got rid of all code that modifies columnNumber, it'd probably work. Which you could then build on, which is what I suggest. Assuming you get rid of the columnNumber modifying code, you're on step 1 in my post. Then go to step 2. etc.

Does it at least make sense why you're seeing $FFs with the explanation in the previous post?
Re: Pallete affects scroll value
by on (#208926)
Done, check the scrolling by pressing A, Up and down
Re: Pallete affects scroll value
by on (#208934)
Fix the CHR! Your file is still 40KB, which probably means you still don't have a .bank 5 and a .org $0000 under that .bank 5.

Glad it mostly works, but there's definitely still something wrong. Every 32 pixels (which I assume is when you update attribute bytes), the scroll position jumps a little vertically.

edit: To be specific: Every 32 horizontal pixels, I mean. Holding A for 32 frames.
Re: Pallete affects scroll value
by on (#209607)
Quuuesstion....

Before I dive into the main problem:
"Why does every time I update my 'pallete'[palette] , the scroll gets messed up?" problem,

There is something wrong with the attribute table. I'm using your (Kasumi) method of updating using nmi timing and when I update the screen data, There are background tiles missing and the attribute doesn't update correctly. Answers?
Also, Fancy a bonus?
1.[*] can you activate an IRQ any where?
2. scroll both the IRQ and the main screen in both directions at the same time? (you know like the Sonic 2 Vs. screen)? example: https://www.youtube.com/watch?v=OgIb5T9HYEc
P.S. This is for a multiplayer option I'm thinking of.
Re: Pallete affects scroll value
by on (#209683)
UPDATE.
Bad example: uses parallax scrolling
Re: Pallete affects scroll value
by on (#209705)
I didn't look at the code, but after 2 minutes of looking at the last .nes file...I see.


1.You aren't zeroing the attribute table of the PPU. Or setting it at all.

No RAM should be assumed to be zero. On a real NES, the screen (attribute table) might be filled with random palettes for the BG.

2. You are still occasionally writing to the PPU outside of v-blank. Not very far outside, but enough to cause occasional jitter while scrolling.
Re: Pallete affects scroll value
by on (#209978)
1. Later... When the 2nd problem is gone.
2. Moving the controller routine makes the jittering stop. Still having rendering problems though.
3. There is a block that keeps rewriting the background Improperly.
4. The "Take Full Advantage of NMI" part of https://wiki.nesdev.com/w/index.php/The ... er_Formats is giving me info but the info given by Kasumi has around the same effect as it is
5. It seems that my Attributes are being written into the column data somehow. Fixing that is the main priority. My "hint" (or blatant truth) is that " [Vblank has a] notification [that] comes in the form of an NMI, or "non-maskable interrupt". ... " [When] the PPU starts VBlank again, the PPU will attempt to notify you that this has happened. It does this by sending an NMI to your program."

Edit: It seems regulation of the attribute table is the answer
Re: Pallete affects scroll value
by on (#210002)
One thing I do, when I'm working on new code (when I'm not sure of PPU behavior)... is make a very minimal test case. So, basically an empty program with just initial code, and a mostly empty nmi, and my test code.

If you are having trouble with attribute tables, perhaps it's because you are writing tiles top to bottom. It's very tricky to write attributes top to bottom.

The attribute table (nametable #0) goes like this...

23c0,23c1,23c2,23c3,23c4,23c5,23c6,23c7
23c8,23c9,23ca,23cb,23cc,23cd,23ce,23cf
23d0,...etc on through 23ff

23c0
23c8 below it
23d0 below that
etc.

So, writing top to bottom adds 32 ($20 hex) but that would skip from 23c0 to 23e0 and miss all the bytes between. You could set a new address for each write to the attribute table.

That is slow, and will probably put you past v-blank. Maybe you could draw the column on 1 frame and draw the attribute on the next frame.
Re: Pallete affects scroll value
by on (#211276)
Ok... Got a question.
I've gotten one of my scrolling bugs fixed (The columnNumber byte was incrementing without the scroll being correct) and the scrolling goes both left and right.
The problem with my system is that if I tap the scrolling, the scroll wont update correctly.
Try it.
P.S. I've labled the needed functions