palette corruption workaround documentation

This commit is contained in:
Michael Miceli 2024-01-11 10:16:28 -05:00
parent 547a7932aa
commit 2f5f1faa3f
5 changed files with 29 additions and 25 deletions

View File

@ -322,7 +322,7 @@ decay that OAM has.
## Sprite Number Encoding
The sprite data in bank 1 is encoded. Except when #$fe, the first byte
specifies the number of entries in the sprite. There there are that many groups
specifies the number of entries in the sprite. Then there are that many groups
of 4-bytes. Each #$4 bytes specify two tiles that are stacked vertically.
Except when the first byte is #$80, these four bytes follow the PPU OAM byte
specification. For details on this data structure,

View File

@ -1833,7 +1833,7 @@ sniper_attack_delay_tbl:
; #$01 - number of bullets to shoot per attack - hiding rifle man
; #$03 - number of bullets to shoot per attack - boss screen rifle man
sniper_bullet_attack_count_tbl:
.byte $03, $01,$03
.byte $03,$01,$03
; rifle man - pointer 3
sniper_routine_02:

View File

@ -177,7 +177,7 @@ handle_sound_slots:
; * y - channel register offset, e.g. #$00 (pulse 1 channel), #$04 (pulse 2 channel), #$08 (triangle channel), #$0c (noise/dmc channel)
@sound_slot_loop:
stx SOUND_CURRENT_SLOT ; set the current sound slot to the current loop index
sty SOUND_CHNL_REG_OFFSET ; set sound channel config register offset (#$00, #$04, $08, or #$0c)
sty SOUND_CHNL_REG_OFFSET ; set sound channel config register offset (#$00, #$04, #$08, or #$0c)
lda SOUND_CODE,x ; load sound code for sound slot
beq @prep_next_loop ; prep to move to next sound slot, or exit if looped through all slots
tay ; sound slot has a sound code, transfer sound code to offset register y
@ -434,7 +434,7 @@ read_low_sound_cmd:
pulse_sustain_note:
tya ; transfer sound code read offset (#$00) to a
pha ; backup y to the stack
ldy SOUND_CHNL_REG_OFFSET ; load sound channel config register offset (#$00, #$04, $08, or #$0c)
ldy SOUND_CHNL_REG_OFFSET ; load sound channel config register offset (#$00, #$04, #$08, or #$0c)
sec ; set carry flag in preparation for subtraction
sbc VIBRATO_DELAY,x ; negate vibrato duration (or #$100 - vibrato duration)
; y - VIBRATO_DELAY,x --> #$00 - VIBRATO_DELAY,x
@ -1266,7 +1266,7 @@ ldx_pulse_triangle_reg:
; exit with x set to SOUND_CHNL_REG_OFFSET and the carry clear
@clc_exit:
clc ; clear carry to signal to update sound register
ldx SOUND_CHNL_REG_OFFSET ; load sound channel config register offset (#$00, #$04, $08, or #$0c)
ldx SOUND_CHNL_REG_OFFSET ; load sound channel config register offset (#$00, #$04, #$08, or #$0c)
pla ; restore a from stack
rts
@ -1332,7 +1332,7 @@ init_pulse_channel:
tax
lda SOUND_CODE,x
beq sound_code_00 ; branch if sound code is #$00
ldy SOUND_CHNL_REG_OFFSET ; load sound channel config register offset (#$00, #$04, $08, or #$0c)
ldy SOUND_CHNL_REG_OFFSET ; load sound channel config register offset (#$00, #$04, #$08, or #$0c)
jsr mute_unmute_pulse_channel ; mutes/unmutes pulse wave channel based on pause state
ldx SOUND_CURRENT_SLOT ; load current sound slot
rts
@ -1484,8 +1484,8 @@ bank_1_unused_label_00:
stx $e6
lda $010a
beq @pop_and_exit
stx $010a ; set sound channel config register offset (#$00, #$04, $08, or #$0c)
stx SOUND_CHNL_REG_OFFSET ; set sound channel config register offset (#$00, #$04, $08, or #$0c)
stx $010a ; set sound channel config register offset (#$00, #$04, #$08, or #$0c)
stx SOUND_CHNL_REG_OFFSET ; set sound channel config register offset (#$00, #$04, #$08, or #$0c)
jsr init_pulse_channel
@pop_and_exit:

View File

@ -456,7 +456,7 @@ game_end_routine_04:
beq load_credits_line_text ; always branch to draw blank line of tiles (ending_credits_00)
@draw_next_line:
lda $42 ; load line credits text offset (initialized to 0 in level_routine_05 clear_memory_starting_a_x)
lda $42 ; load line credits text offset (initialized to 0 in level_routine_05 clear_memory_starting_at_x)
inc $42 ; increment credits line offset
asl ; double since each entry is #$02 bytes
tay

View File

@ -1187,13 +1187,14 @@ player_mode_1d_table:
p2_game_over_status_tbl:
.byte $01,$00
; clear memory addresses $0028 to $00f0 then CPU_SPRITE_BUFFER up to CPU_GRAPHICS_BUFFER
; clear memory addresses $0028 to $00f0 then CPU_SPRITE_BUFFER up to CPU_GRAPHICS_BUFFER (not including) [$300-$700)
clear_memory_3:
ldx #$28
; clear x to #$f0 bytes
; then clear CPU_SPRITE_BUFFER ($300) up to CPU_GRAPHICS_BUFFER ($700)
clear_memory_starting_a_x:
; clears memory [x-$f0) and [$300-$700]
; input
; * x - starting memory address to clear (inclusive)
clear_memory_starting_at_x:
lda #$00
@loop:
@ -2653,13 +2654,14 @@ write_cpu_graphics_buffer_to_ppu:
@read_cpu_mem_to_ppu:
lda $08 ; read previous high byte of PPU write address
cmp #$3f ; compare $08 to #$3f
bne @continue ; skip ahead if $08 is not equal to #$3f
sta PPUADDR ; !(WHY?) the following code doesn't make sense to me
lda #$00 ; it sets the PPUADDR to #$3f00, then #$0000
sta PPUADDR ; but this is overwritten in the next few lines
sta PPUADDR ; that would have been executed regardless of what $08 was
sta PPUADDR ; this code seems to be able to be removed without issue !(WHY?)
cmp #$3f ; compare $08 to #$3f (seeing if palette write)
bne @continue ; skip ahead if $08 is not equal to #$3f (not writing palette)
sta PPUADDR ; !(OBS) I think this is attempting to prevent the NTSC NES palette corruption bug
lda #$00 ; the palette can get corrupted after writes to it
; the workaround is to update the PPUADDR twice after writing to palette memory
sta PPUADDR ; ref: https://www.nesdev.org/wiki/PPU_registers#Address_($2006)_%3E%3E_write_x2
sta PPUADDR ; (1) set PPUADDR to $3f00, then (2) set PPUADDR outside palette memory (in this case $0000)
sta PPUADDR ; these steps prevent palette corruption
; CPU address $cbe5
@continue:
@ -2787,10 +2789,12 @@ write_palette_colors_to_ppu:
dex
bne @loop
lda #$3f
sta PPUADDR ; set ppu write address to $3f00
stx PPUADDR ; store low byte of $3f00
stx PPUADDR ; be sure it wrote correctly
stx PPUADDR ; be sure it wrote correctly
sta PPUADDR ; !(OBS) I think this is attempting to prevent the NTSC NES palette corruption bug
stx PPUADDR ; the palette can get corrupted after writes to it
; the workaround is to update the PPUADDR twice after writing to palette memory
; ref: https://www.nesdev.org/wiki/PPU_registers#Address_($2006)_%3E%3E_write_x2
stx PPUADDR ; (1) set PPUADDR to $3f00, then (2) set PPUADDR outside palette memory (in this case $0000)
stx PPUADDR ; these steps prevent palette corruption after writing to the palette memory
stx NUM_PALETTES_TO_LOAD ; set number of palettes to load to #$3f
; don't think this value is ever read when it's #$3f, overwritten later
@ -3231,7 +3235,7 @@ level_routine_05:
lda P2_CURRENT_WEAPON ; current weapon code (player 2)
sta $11 ; temporarily store current weapon in $11
ldx #$40 ; x = #$40 (set to 30 for game over after lvl 1)
jsr clear_memory_starting_a_x ; clear level header data, player data, sprite buffer, and super-tile buffer
jsr clear_memory_starting_at_x ; clear level header data, player data, sprite buffer, and super-tile buffer (memory [$40-$f0) and [$300-$700])
lda BOSS_DEFEATED_FLAG ; 0 = boss not defeated, 1 = boss defeated
beq show_game_over_screen ; in level_routine_05 and boss wasn't defeated, game over
; unless demo mode (shouldn't happen because demos don't reach end of level), then just set DEMO_LEVEL_END_FLAG and exit