mirror of
https://github.com/daniel5151/ANESE.git
synced 2025-04-02 10:32:00 -04:00
717 lines
14 KiB
ArmAsm
Executable file
Vendored
717 lines
14 KiB
ArmAsm
Executable file
Vendored
zp_res nmi_count
|
|
zp_res nmi_ready
|
|
|
|
; Generates the load and store templates
|
|
; for using A*$100 as a buffer.
|
|
load_transfer_templates:
|
|
sta template_subst_ptr+1
|
|
lda #$00
|
|
sta template_subst_ptr+0
|
|
|
|
setw template_targetptr, load_cool_graphics
|
|
setw template_sourceptr, loader_template_begin
|
|
setb template_bytecount, (loader_template_end-loader_template_begin+3)&~3
|
|
jsr load_template
|
|
|
|
setw template_targetptr, transfer_cool_graphics
|
|
setw template_sourceptr, writer_template_begin
|
|
setb template_bytecount, (writer_template_end-writer_template_begin+3)&~3
|
|
;jmp load_template
|
|
load_template:
|
|
ldy #0
|
|
ldx template_subst_ptr+1
|
|
@loop: lda (template_sourceptr),y
|
|
cmp #$FF
|
|
beq @patch
|
|
@maybe_wrap:
|
|
sta (template_targetptr),y
|
|
iny
|
|
cpy template_bytecount
|
|
bne @loop
|
|
rts
|
|
@patch: lda template_subst_ptr+0
|
|
sta (template_targetptr),y
|
|
iny
|
|
txa
|
|
jmp @maybe_wrap
|
|
|
|
.pushseg
|
|
.segment "TEMPLATE1"
|
|
writer_template_begin:
|
|
lda #0
|
|
sta gfx_source_ppuptr+0
|
|
sta gfx_source_ppuptr+1
|
|
writer_template_skip_sourceptr:
|
|
sty gfx_bytecount
|
|
lda PPUSTATUS ; reset flip-flop
|
|
: jsr load_cool_graphics
|
|
lda addr+1
|
|
sta PPUADDR ; poke high 6 bits
|
|
lda addr+0
|
|
sta PPUADDR ; poke low 8 bits
|
|
ldy #0
|
|
: .repeat 8
|
|
lda $FFFF,y
|
|
sta PPUDATA
|
|
iny
|
|
.endrepeat
|
|
cpy gfx_bytecount
|
|
bne :-
|
|
inc gfx_source_ppuptr+1
|
|
inc addr +1
|
|
dex
|
|
bne :--
|
|
rts
|
|
writer_template_end:
|
|
|
|
|
|
.segment "TEMPLATE2"
|
|
loader_template_begin:
|
|
; Load Y bytes of data from PPU address "gfx_source_ppuptr" into oam_buffer.
|
|
lda gfx_source_ppuptr+1
|
|
sta PPUADDR ; poke high 6 bits
|
|
lda gfx_source_ppuptr+0
|
|
sta PPUADDR ; poke low 8 bits
|
|
lda PPUDATA
|
|
ldy #0
|
|
: .repeat 4
|
|
lda PPUDATA
|
|
sta $FFFF,y
|
|
iny
|
|
.endrepeat
|
|
cpy gfx_bytecount
|
|
bne :-
|
|
rts
|
|
|
|
loader_template_end:
|
|
|
|
|
|
.popseg
|
|
|
|
do_cool_graphics:
|
|
; Disable the rendering while transferring data from/to PPU memory.
|
|
jsr console_hide
|
|
|
|
; Just for the sake of being peculiar, all our graphics data is in VROM.
|
|
; Not only that, the code that loads the data from VROM is also in VROM!
|
|
; And not only that, the code that shows the data is there too.
|
|
|
|
; load_transfer_templates:
|
|
; Copies loader_template and writer_template into RAM.
|
|
; Patches the oam_buffer offset into the code.
|
|
; load_cool_graphics:
|
|
; This function is in RAM. It loads data from VROM into buffer.
|
|
; transfer_cool_graphics:
|
|
; This function is in RAM. It writes data from buffer into PPU memory.
|
|
|
|
; Load our graphics bootstrap code from VROM
|
|
set_vrom_page 1
|
|
setw gfx_source_ppuptr, page2_prefix_size
|
|
|
|
@size = $500 ;show_cool_graphics_size + $100
|
|
ldx #>@size
|
|
|
|
ldy #0
|
|
: setb gfx_bytecount,0
|
|
txa
|
|
bne :+
|
|
lda #<@size
|
|
beq @rts
|
|
sta gfx_bytecount
|
|
: txa
|
|
pha
|
|
tya
|
|
pha
|
|
clc
|
|
adc #>show_cool_graphics-1 ;-1 because we also load OAM template (gfx.spr.bin)
|
|
jsr load_transfer_templates
|
|
jsr load_cool_graphics
|
|
inc gfx_source_ppuptr+1
|
|
pla ;y
|
|
tay
|
|
iny
|
|
pla ;x
|
|
tax
|
|
dex
|
|
bpl :--
|
|
@rts:
|
|
; Jump into the bootstrap code.
|
|
jmp show_cool_graphics ; skip gfx.spr.bin
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
.segment "CHARS_P2"
|
|
@begin:
|
|
.incbin "gfx.nta.bin"
|
|
.incbin "gfx.attr.bin"
|
|
|
|
; The following begins at $0400.
|
|
.incbin "gfx.spr2.chr"
|
|
|
|
; The following begins at $0400+sprite_data_size.
|
|
.incbin "gfx.pal.bin"
|
|
@end:
|
|
page2_prefix_size = @end-@begin
|
|
|
|
.incbin "gfx.spr.bin"
|
|
|
|
.segment "CHARS_P2"
|
|
; THIS CODE IS STORED IN VROM. (PAGE 1, OFFSET $0520)
|
|
show_cool_graphics_template_begin:
|
|
; Because this code actually resides in VROM, and later in system
|
|
; RAM, we must use this c_DELTA factor in any and all absolute
|
|
; addresses (jmp,jsr etc) within this code referring to itself.
|
|
c_DELTA = show_cool_graphics_template_begin - show_cool_graphics
|
|
|
|
lda #1
|
|
sta console_palettes_disabled
|
|
|
|
text_white
|
|
jsr print_spacer
|
|
jsr print_str_
|
|
; 0123456789ABCDEF0123456789ABCD
|
|
.byte " This next test will take a while.",newline ;DO_DTE
|
|
.byte " In order to distract you with",newline ;DO_DTE
|
|
.byte " entertainment, art is provided.",newline ;DO_DTE
|
|
.byte " Contemplate on the art while",newline ;DO_DTE
|
|
.byte " the test is in progress.",newline ;DO_DTE
|
|
.byte newline,newline,newline ;DO_DTE
|
|
.byte 0 ;DO_DTE
|
|
|
|
jsr c_test_read_buffer_fade_blank_delay - c_DELTA
|
|
|
|
lda #0
|
|
sta PPUCTRL
|
|
sta PPUMASK
|
|
|
|
;set_vrom_page 1
|
|
lda #>oam_buffer
|
|
jsr load_transfer_templates
|
|
|
|
; Transfer $400 bytes of data to $2C00 (second nta regadless of mirroring)
|
|
setw addr, $2C00
|
|
ldx #4
|
|
ldy #0
|
|
jsr transfer_cool_graphics
|
|
|
|
; Transfer $20 bytes of data to $3FE0
|
|
setw addr, $3FE0
|
|
setw gfx_source_ppuptr, (page2_prefix_size-$20)
|
|
ldx #1
|
|
ldy #$20
|
|
jsr transfer_cool_graphics + (writer_template_skip_sourceptr-writer_template_begin)
|
|
|
|
; Initialize scrolling
|
|
lda #230
|
|
sta scroll_framecount
|
|
lda #1
|
|
sta scroll_y
|
|
lda #0
|
|
sta scroll_y+1
|
|
sta scroll_ydelta
|
|
sta scroll_ydelta+1
|
|
sta scroll_framecount+1
|
|
sta nmi_ready
|
|
|
|
jsr console_show
|
|
set_vrom_page 0
|
|
|
|
jsr c_test_read_buffer_fade_visible_delay_init - c_DELTA
|
|
|
|
lda #$00
|
|
sta nmi_count
|
|
sta PPUSCROLL
|
|
lda #1
|
|
sta PPUSCROLL
|
|
|
|
; Load $100 bytes of actual sprite data to oam_buffer
|
|
ldx #0
|
|
: lda CoolGraphicsSpr, x
|
|
sta oam_buffer,x
|
|
inx
|
|
bne :-
|
|
|
|
jsr wait_vbl_optional
|
|
lda #$A0 ;Select background graphics page 0 & nametable 0
|
|
sta PPUCTRL ; & 16pix sprites & enable NMI
|
|
lda #($F * 2)
|
|
sta PPUMASK ;Show background graphics and sprites
|
|
|
|
c_main_loop:
|
|
lda #0
|
|
c_end_flag_loc = *-1
|
|
bne @end_loop
|
|
|
|
jsr c_update_scrolling - c_DELTA - $800
|
|
jsr c_update_sprites - c_DELTA - $1000
|
|
jsr c_update_split_points - c_DELTA - $1800
|
|
jsr c_read_joypad - c_DELTA - $1800
|
|
|
|
; All set. Wait for NMI
|
|
inc nmi_ready
|
|
: lda nmi_count
|
|
beq :-
|
|
dec nmi_count
|
|
dec nmi_ready
|
|
beq c_main_loop
|
|
|
|
@end_loop:
|
|
lda #0
|
|
sta PPUCTRL ; disable NMI
|
|
sta console_palettes_disabled
|
|
jsr console_hide
|
|
set_vrom_page 0
|
|
rts
|
|
|
|
c_nmi_handler:
|
|
; That's right, our NMI handler is in RAM.
|
|
lda nmi_ready
|
|
beq @skip_nmi_reentry
|
|
lda nmi_count
|
|
bne @skip_nmi_reentry
|
|
|
|
sta bus_conflict_antidote+0 ; VROM page 0
|
|
lda PPUSTATUS
|
|
|
|
jsr c_test_read_buffer_fade_visible_delay_callback - c_DELTA
|
|
|
|
ldx scroll_y
|
|
ldy #0
|
|
|
|
sty PPUSCROLL ;0
|
|
stx PPUSCROLL ;scroll_y
|
|
|
|
sty SPRADDR ;sprite 0
|
|
lda #>oam_buffer
|
|
sta $4014
|
|
|
|
lda #$A0 ;Select background graphics page 1 & nametable 0
|
|
sta PPUCTRL ; & 16pix sprites & enable NMI
|
|
|
|
ldy #($F*2)
|
|
lda #2
|
|
bit joy_cur
|
|
beq :+
|
|
ldy #($F*2)-16
|
|
: sty PPUMASK
|
|
|
|
jsr c_perform_splits - c_DELTA - $1000
|
|
|
|
inc nmi_count
|
|
@skip_nmi_reentry:
|
|
rti
|
|
|
|
|
|
c_update_sprites:
|
|
lda scroll_y
|
|
clc
|
|
adc #17
|
|
sta scroll_delays
|
|
|
|
ldy #$F8
|
|
ldx #$E0
|
|
c_sprloop:
|
|
.repeat 8,n
|
|
lda CoolGraphicsSpr -n*$20,x
|
|
sec
|
|
sbc scroll_delays
|
|
bcc :+
|
|
tya
|
|
: sta oam_buffer -n*$20 ,x
|
|
.endrepeat
|
|
|
|
inx
|
|
inx
|
|
inx
|
|
inx
|
|
bne c_sprloop
|
|
rts
|
|
|
|
c_perform_splits:
|
|
; SECTION 0 (BEFORE GRAPHICS):
|
|
; 0.$0000 - BACKGROUND: TEXT.
|
|
; 0.$1000 - unused
|
|
|
|
lda scroll_delays+0
|
|
beq :+
|
|
ldx #50
|
|
jsr delay_n_scanlines_ntsc
|
|
|
|
set_vrom_page 2
|
|
lda #$B1 ;Select background graphics page 1 & nametable 0
|
|
sta PPUCTRL ; & 16pix sprites & enable NMI
|
|
; SECTION 1:
|
|
; 2.$0000 - SPRITES.
|
|
; 2.$1000 - BACKGROUND
|
|
|
|
lda scroll_delays+4
|
|
beq :+
|
|
ldx #50
|
|
jsr delay_n_scanlines_ntsc
|
|
|
|
set_vrom_page 1
|
|
; SECTION 2:
|
|
; 1.$0000 - SPRITES. code unused
|
|
; 1.$1000 - BACKGROUND
|
|
|
|
lda scroll_delays+5
|
|
beq :+
|
|
ldx #20
|
|
jsr delay_n_scanlines_ntsc
|
|
|
|
set_vrom_page 0
|
|
; SECTION 3:
|
|
; 0.$0000 - unused
|
|
; 0.$1000 - SPRITES & BACKGROUND
|
|
|
|
lda scroll_delays+6
|
|
beq :+
|
|
ldx #20
|
|
jsr delay_n_scanlines_ntsc
|
|
|
|
set_vrom_page 2
|
|
lda #$A1 ;Select background graphics page 0 & nametable 0
|
|
sta PPUCTRL ; & 16pix sprites & enable NMI
|
|
; SECTION 4:
|
|
; 2.$0000 - SPRITES & BACKGROUND
|
|
; 2.$1000 - unused
|
|
|
|
: rts
|
|
|
|
|
|
c_update_split_points:
|
|
c_MAXY=242
|
|
c_OFFSET=255
|
|
|
|
lda #255
|
|
sta scroll_delays+0
|
|
sta scroll_delays+1
|
|
sta scroll_delays+2
|
|
sta scroll_delays+3
|
|
|
|
ldx scroll_y
|
|
dex
|
|
stx scroll_delays+6
|
|
|
|
.macro sub16 v
|
|
lda #<(v)
|
|
sec
|
|
sbc scroll_delays+6
|
|
tax
|
|
lda #>(v)
|
|
sbc #0
|
|
.endmacro
|
|
|
|
sub16 c_OFFSET+(0)
|
|
bne @skip0
|
|
stx scroll_delays+0
|
|
|
|
sub16 c_OFFSET+(64)
|
|
bne @skip0
|
|
stx scroll_delays+1
|
|
|
|
sub16 c_OFFSET+(128)
|
|
bne @skip1
|
|
stx scroll_delays+2
|
|
|
|
sub16 c_OFFSET+(184)
|
|
bne @skip2
|
|
stx scroll_delays+3
|
|
|
|
@skip2:
|
|
@skip1:
|
|
@skip0:
|
|
lda #0
|
|
sta scroll_delays+4
|
|
sta scroll_delays+5
|
|
sta scroll_delays+6
|
|
|
|
lda scroll_delays+0
|
|
tay
|
|
cmp #c_MAXY
|
|
bcc :+
|
|
ldy #0
|
|
: sty scroll_delays+0
|
|
;
|
|
lda scroll_delays+1
|
|
cmp #c_MAXY
|
|
bcs :+
|
|
sec
|
|
sbc scroll_delays+0
|
|
sta scroll_delays+4
|
|
;
|
|
lda scroll_delays+2
|
|
cmp #c_MAXY
|
|
bcs :+
|
|
sec
|
|
sbc scroll_delays+1
|
|
sta scroll_delays+5
|
|
;
|
|
lda scroll_delays+3
|
|
cmp #c_MAXY
|
|
bcs :+
|
|
sec
|
|
sbc scroll_delays+2
|
|
sta scroll_delays+6
|
|
:
|
|
rts
|
|
|
|
c_update_scrolling:
|
|
lda scroll_framecount+1
|
|
cmp #2
|
|
beq c_scroll_finish
|
|
bcs c_scroll_updated
|
|
;
|
|
inc scroll_framecount
|
|
bne :+
|
|
inc scroll_framecount+1
|
|
: lda scroll_y+1
|
|
clc
|
|
adc scroll_ydelta
|
|
sta scroll_y+1
|
|
lda scroll_y
|
|
adc scroll_ydelta+1
|
|
sta scroll_y
|
|
lda scroll_y
|
|
cmp #$A0
|
|
bcs c_past_end
|
|
lsr
|
|
lsr
|
|
lsr
|
|
lsr
|
|
tay
|
|
lda scroll_ydelta
|
|
clc
|
|
adc c_scroll_ydeltatable - c_DELTA - $1000,y
|
|
sta scroll_ydelta
|
|
lda scroll_ydelta+1
|
|
adc #0
|
|
sta scroll_ydelta+1
|
|
jmp c_scroll_updated - c_DELTA
|
|
c_past_end:
|
|
lda scroll_ydelta
|
|
sec
|
|
sbc #15
|
|
sta scroll_ydelta
|
|
lda scroll_ydelta+1
|
|
sbc #0
|
|
sta scroll_ydelta+1
|
|
jmp c_scroll_updated - c_DELTA
|
|
c_scroll_finish:
|
|
inc scroll_framecount+1
|
|
lda #238
|
|
sta scroll_y
|
|
c_scroll_updated:
|
|
rts
|
|
c_scroll_ydeltatable:
|
|
.byt 1,1,1,1,3, 6,10,15,20,24
|
|
|
|
c_read_joypad:
|
|
ldy #1
|
|
sty JOY1
|
|
dey
|
|
sty JOY1
|
|
ldy #8
|
|
: lda JOY1
|
|
sta joy_temp
|
|
lsr
|
|
ora joy_temp
|
|
lsr
|
|
ror joy_cur
|
|
dey
|
|
bne :-
|
|
rts
|
|
|
|
|
|
c_test_read_buffer_fade_blank_delay:
|
|
; Because the screen will be blank for 2 seconds,
|
|
; make some kind of sound effect to show that
|
|
; it is somehow expected.
|
|
|
|
setb SNDCHN, 3 ; Enable APU square channels 0,1
|
|
|
|
jsr pre_beep_dual
|
|
|
|
jsr populate_ciram_quick
|
|
; Console is left hidden and rendering disabled
|
|
set_ppuaddr $2E13
|
|
lda PPUDATA
|
|
|
|
begin_test TEST_BUFFER_DELAY_BLANK_2SECONDS
|
|
|
|
jsr pre_beep_length
|
|
jsr pre_beep_length
|
|
jsr pre_beep_length
|
|
jsr long_beep
|
|
delay (CLOCK_RATE*161)/100
|
|
fail_if_ppuread_y_not $8A ; $77+$13
|
|
|
|
jsr final_beep
|
|
begin_test TEST_BUFFER_DELAY_BLANK_1FRAME
|
|
delay 40000 ; 1-2 frames
|
|
lda PPUDATA
|
|
cmp #$8B
|
|
jmp fail_current_test_ifNE
|
|
|
|
|
|
|
|
zp_res test_position
|
|
zp_res test_ptr, 2
|
|
zp_res remaining_delay, 2
|
|
|
|
c_test_read_buffer_fade_visible_delay_callback:
|
|
bit test_position
|
|
bmi @elapse_delay
|
|
.macro test_set__addr_and_load
|
|
lda (test_ptr),y
|
|
sta PPUADDR
|
|
dey ;2
|
|
lda (test_ptr),y
|
|
sta PPUADDR
|
|
lda PPUDATA
|
|
.endmacro
|
|
@choose_next_test:
|
|
begin_test TEST_BUFFER_DELAY_INTERNAL
|
|
;bit PPUSTATUS
|
|
; Check if we are in end of list of tests
|
|
ldy #0
|
|
lda (test_ptr),y
|
|
beq @all_done
|
|
;
|
|
; Set flag that indicates a test is in progress
|
|
dec test_position
|
|
;
|
|
; Load test specifications
|
|
ldy #5
|
|
lda (test_ptr),y
|
|
sta remaining_delay+1
|
|
dey ;4
|
|
lda (test_ptr),y
|
|
sta remaining_delay+0
|
|
dey ;3
|
|
test_set__addr_and_load
|
|
lda PPUDATA
|
|
ldy #1
|
|
cmp (test_ptr),y
|
|
jsr fail_current_test_ifNE
|
|
ldy #3
|
|
test_set__addr_and_load
|
|
ldy #0
|
|
lda (test_ptr),y
|
|
jmp begin_test_
|
|
@all_done:
|
|
setb cool_graphics_end_flag, 1
|
|
@done: rts
|
|
|
|
@elapse_delay:
|
|
lda remaining_delay+0
|
|
sec
|
|
sbc #1
|
|
sta remaining_delay+0
|
|
lda remaining_delay+1
|
|
sbc #0
|
|
sta remaining_delay+1
|
|
ora remaining_delay+0
|
|
bne @done
|
|
@read_result:
|
|
jsr final_beep
|
|
|
|
ldy #3
|
|
test_set__addr_and_load
|
|
dey ;1
|
|
cmp (test_ptr),y
|
|
jsr fail_current_test_ifNE
|
|
; Reset flag, to indicate no test is in progress
|
|
inc test_position
|
|
; Jump to next test
|
|
lda test_ptr
|
|
clc
|
|
adc #6
|
|
sta test_ptr
|
|
lda test_ptr+1
|
|
adc #0
|
|
sta test_ptr+1
|
|
jmp @choose_next_test - c_DELTA
|
|
|
|
c_test_read_buffer_fade_visible_delay_init:
|
|
setb test_position, 0
|
|
sta remaining_delay+0
|
|
sta remaining_delay+1
|
|
setw test_ptr, test_read_buffer_fade_visible_delay_schedule
|
|
rts
|
|
|
|
|
|
cool_graphics_end_flag = c_end_flag_loc - c_DELTA
|
|
nmi = c_nmi_handler - c_DELTA
|
|
|
|
show_cool_graphics_size = * - show_cool_graphics_template_begin
|
|
|
|
|
|
|
|
|
|
|
|
.segment "CHARS_GFX3a"
|
|
.incbin "gfx.spr.page3_A.chr"
|
|
.segment "CHARS_GFX3b"
|
|
.incbin "gfx.spr.page3_B.chr"
|
|
|
|
|
|
.segment "CHARS_SPR1"
|
|
.incbin "gfx.spr1.chr"
|
|
.segment "CHARS_GFX1"
|
|
.incbin "gfx.page1.chr"
|
|
.segment "CHARS_GFX2"
|
|
.incbin "gfx.page2.chr"
|
|
|
|
|
|
.segment "CHARS_6C00"
|
|
.incbin "gfx.6c00.bin"
|
|
|
|
.segment "CHARS_P4"
|
|
.incbin "gfx.bank4.bin"
|
|
|
|
.segment "STACK"
|
|
transfer_cool_graphics: .res (writer_template_end-writer_template_begin+3)&~3
|
|
; This function is stored in $100-$15F. Though the memory area
|
|
; is reserved for stack, we expect the stack to require
|
|
; considerably less space.
|
|
; There's no real REASON for it to be stored in this contrived
|
|
; manner other than to provide some unusual code for an emulator
|
|
; author to test with, and occassional fun for anyone who chooses
|
|
; to try to reverse engineer an assembler trace.
|
|
|
|
.segment "ZEROPAGE"
|
|
; Load X times Y bytes of data from PPU address $0000, store
|
|
; to PPU address "addr". Use temporary buffer as configured by
|
|
; load_transfer_templates.
|
|
load_cool_graphics: .res ((loader_template_end-loader_template_begin)+3)&~3
|
|
; This function is stored in ZEROPAGE. We don't generally
|
|
; use that much of zeropage room, so it is expected to be
|
|
; available. As a side effect, we get a linker error if
|
|
; the alignment did not work properly, which is good.
|
|
; The disclaimer about real reason applies somewhat, though.
|
|
; We could easily fit both of these functions in BSS.
|
|
|
|
|
|
.segment "OAM_BUF"
|
|
|
|
; OAM cache. Sprite data is calculated into this buffer,
|
|
; and uploaded to the PPU using the $4014 DMA.
|
|
.align $100
|
|
oam_buffer: .res $100
|
|
|
|
.segment "CODE_BUF"
|
|
|
|
.align $100
|
|
CoolGraphicsSpr:
|
|
.res $100
|
|
|
|
; This buffer is for code that runs in the RAM.
|
|
; It is initialized by loading the code from VROM.
|
|
; The real reason disclaimer is heavily leaned on here.
|
|
show_cool_graphics_buf:
|
|
.res show_cool_graphics_size
|
|
|
|
show_cool_graphics = show_cool_graphics_buf+$1800
|