.import _split_list

.segment "ZEROPAGE"

IRQ_INIT:				.res 3
IRQ_CALL:				.res 3
IRQ_START_LINE:			.res 1
IRQ_LINE_OFF:			.res 1
IRQ_SPLIT_LIST:			.res 2


.segment "FIXED"

irq_handlers_list:

	.word irq_empty_init   	,irq_empty			;0
	.word irq_row_adr_init 	,irq_row_adr		;1
	.word irq_nescart_init 	,irq_nescart		;2
	.word irq_roll_fade_init,irq_roll_fade		;4
	.word irq_row_fullx_init,irq_row_fullx		;5
	.word irq_inspired_init ,irq_inspired		;6
	.word irq_dungeon_init	,irq_dungeon		;7
	.word irq_pacman_init	,irq_pacman			;8

	
;------------------------------------------------------------------------------

;void __fastcall__ set_irq_handler(unsigned char id);

.export _set_irq_handler

_set_irq_handler:

	asl a
	asl a
	pha
	tax
	
	lda irq_handlers_list+0,x	;INIT
	ldy irq_handlers_list+1,x
	
	ldx #$40					;RTI
	stx <IRQ_INIT+0
	sta <IRQ_INIT+1
	sty <IRQ_INIT+2
	lda #$4c					;JMP
	sta <IRQ_INIT+0
	
	pla
	tax

	lda irq_handlers_list+2,x	;HANDLER
	ldy irq_handlers_list+3,x
	
	ldx #$40					;RTI
	stx <IRQ_CALL+0
	sta <IRQ_CALL+1
	sty <IRQ_CALL+2
	lda #$4c					;JMP
	sta <IRQ_CALL+0

	rts
	
;------------------------------------------------------------------------------
	
irq_empty_init:

	rts
	
irq_empty:

	sta MMC3_IRQ_DISABLE		;acknowledge
	rti

;------------------------------------------------------------------------------

irq_row_adr_init:

	lda #0
	sta <IRQ_LINE_OFF
	lda #<_split_list
	sta <IRQ_SPLIT_LIST+0
	lda #>_split_list
	sta <IRQ_SPLIT_LIST+1
	
	rts
	
irq_row_adr:

	sta MMC3_IRQ_DISABLE
	
	pha
	txa
	pha
	tya
	pha

	lda #7
	sta MMC3_IRQ_LATCH
	sta MMC3_IRQ_RELOAD
	sta MMC3_IRQ_DISABLE
	sta MMC3_IRQ_ENABLE
	
	lda #21				;2
	jsr timing_delay	;25+21
	
	ldx #0
	ldy <IRQ_LINE_OFF
	lda (IRQ_SPLIT_LIST),y
	iny
	sta PPU_ADDR
	lda (IRQ_SPLIT_LIST),y
	stx PPU_SCROLL
	stx PPU_SCROLL
	sta PPU_ADDR
	iny
	sty <IRQ_LINE_OFF
	
	pla
	tay
	pla
	tax
	pla
	
	rti
	
;------------------------------------------------------------------------------

.import _nescart_bank_prg
.import _nescart_bank_off

irq_nescart_init:

	lda _nescart_bank_prg
	beq @skip

	jsr mmc3_set_prg_temp
	
	lda _nescart_bank_off+0
	sta <IRQ_SPLIT_LIST+0
	lda _nescart_bank_off+1
	clc
	adc #$80
	sta <IRQ_SPLIT_LIST+1
	
	ldy #0
	
@copy:

	lda (IRQ_SPLIT_LIST),y
	iny
	sta _split_list,y
	cpy #176
	bne @copy
	
	jsr mmc3_restore_prg
	
@skip:

	lda #<_split_list
	sta <IRQ_SPLIT_LIST+0
	lda #>_split_list
	sta <IRQ_SPLIT_LIST+1
	
	rts
	

	;some weird timing glitch happened after 128th line, likely related to
	;combination of the table/code/split list page alignments
	;so the 114/114/113 pattern is altered via table

	.align 256
	
irq_nescart_timings:

	.repeat 27
	.byte 54,55,55
	.endrepeat
	.byte 53,53
	.repeat 50
	.byte 53,54,54
	.endrepeat

	.align 256
	
irq_nescart:

	sta MMC3_IRQ_DISABLE
	
	pha
	txa
	pha
	tya
	pha

	lda #53				;2
	jsr timing_delay	;25+53

	ldy #0
	
_irq_loff_0:

	lda irq_nescart_timings,y	;4+
	jsr timing_delay			;25+A

	ldx #0						;2
	lda (IRQ_SPLIT_LIST),y		;5+	the extra clock is inserted when page boundary crossed
	iny							;2
	stx PPU_ADDR				;4
	sta PPU_SCROLL				;4
	and #$f8					;2
	asl a						;2
	asl a						;2
	stx PPU_SCROLL				;4 these two writes should be done on the hblank
	sta PPU_ADDR				;4
	
	cpy #176					;2		height of the raster
	bne _irq_loff_0				;2/3

	lda <PPU_MASK_VAR			;disable background from now on
	and #$f7
	sta PPU_MASK
	
	pla
	tay
	pla
	tax
	pla
	
	rti

	
;------------------------------------------------------------------------------

irq_roll_fade_init:

	lda #<_split_list
	sta <IRQ_SPLIT_LIST+0
	lda #>_split_list
	sta <IRQ_SPLIT_LIST+1
	lda #0
	sta <IRQ_LINE_OFF
	
	lda #200				;2
	jsr timing_delay		;25+A
	lda #180				;2
	jsr timing_delay		;25+A
	
	jsr irq_roll_fade_block
	
	rts
	
	
	
irq_roll_fade_block:

	lda <PPU_MASK_VAR
	eor #$e0
	sta PPU_MASK
	
	ldx #ERO_HEIGHT/5
	ldy <IRQ_LINE_OFF
	
	;113.6 per line, in groups of five
	
@rollfade:
	
	.repeat 4
	
	lda #69					;2
	jsr timing_delay		;25+A
	
	lda (IRQ_SPLIT_LIST),y	;5+
	iny						;2
	sta PPU_SCROLL			;4
	lda #0					;2
	sta PPU_SCROLL			;4=113
	
	.endrepeat
	
	lda #67					;2
	jsr timing_delay		;25+A

	lda (IRQ_SPLIT_LIST),y	;5+
	iny						;2
	sta PPU_SCROLL			;4
	lda #0					;2
	sta PPU_SCROLL			;4
	
	dex						;2
	bne @rollfade			;2/3=568
	
	sty <IRQ_LINE_OFF
	
	lda <PPU_MASK_VAR
	sta PPU_MASK
	rts
	
	
	
irq_roll_fade:

	sta MMC3_IRQ_DISABLE
	
	pha
	txa
	pha
	tya
	pha

	lda #50					;2
	jsr timing_delay		;25+A
	
	jsr irq_roll_fade_block

	pla
	tay
	pla
	tax
	pla
	
	rti
	
	
	
;------------------------------------------------------------------------------

irq_row_fullx_init:

	lda #0
	sta <IRQ_LINE_OFF
	lda #<_split_list
	sta <IRQ_SPLIT_LIST+0
	lda #>_split_list
	sta <IRQ_SPLIT_LIST+1
	
	rts
	
irq_row_fullx:

	sta MMC3_IRQ_DISABLE
	
	pha
	txa
	pha
	tya
	pha

	lda #7
	sta MMC3_IRQ_LATCH
	sta MMC3_IRQ_RELOAD
	sta MMC3_IRQ_DISABLE
	sta MMC3_IRQ_ENABLE
	
	lda #11					;2
	jsr timing_delay		;25+11

	ldy <IRQ_LINE_OFF

	lda (IRQ_SPLIT_LIST),y		;bottom byte of X coord
	iny
	tax
	lda <PPU_CTRL_VAR
	and #$fe
	ora (IRQ_SPLIT_LIST),y		;top bit of X coord
	iny
	sty <IRQ_LINE_OFF

	stx PPU_SCROLL				;this write should be done just before end of the line, but not in hblank
	stx PPU_SCROLL
	sta PPU_CTRL	

	pla
	tay
	pla
	tax
	pla
	
	rti
	
;------------------------------------------------------------------------------

irq_inspired_init:

	rts
	
irq_inspired:

	sta MMC3_IRQ_DISABLE
	
	pha
	txa
	pha
	tya
	pha
	
	lda <PPU_CTRL_VAR		;switch to the second table, irq's stop to work from this point to the next frame
	ora #$10
	sta PPU_CTRL
	
	ldx #16
:
	lda #113-25
	jsr timing_delay	;25+A
	dex
	bne :-
	
	lda #0
	sta PPU_MASK

	lda #>INSPIRED_NT_ADR
	sta <IRQ_SPLIT_LIST+1
	lda #<INSPIRED_NT_ADR
	sta <IRQ_SPLIT_LIST+0

	ldy #0
:

	lda <IRQ_SPLIT_LIST+1
	sta PPU_ADDR
	lda <IRQ_SPLIT_LIST+0
	sta PPU_ADDR
	
	.repeat 14,N
	lda _update_list+N,y
	sta PPU_DATA
	.endrepeat
		
	lda <IRQ_SPLIT_LIST+0
	clc
	adc #32
	sta <IRQ_SPLIT_LIST+0
	bcc :+
	inc <IRQ_SPLIT_LIST+1
:

	tya
	clc
	adc #14
	tay
	
	cpy #14*14
	bne :--
	
	lda #0
	sta PPU_ADDR
	sta PPU_ADDR
	
	lda <PPU_MASK_VAR	;interestingly without enabling rendering it works everywhere but Mesen, where it glitches up all sprite updates
	sta PPU_MASK
	
	pla
	tay
	pla
	tax
	pla
	
	rti
	
	
;------------------------------------------------------------------------------

irq_dungeon_init:

	rts
	
irq_dungeon_set_nt:

	lda <IRQ_SPLIT_LIST+1
	sta PPU_ADDR
	lda <IRQ_SPLIT_LIST+0
	sta PPU_ADDR
	
	lda <IRQ_SPLIT_LIST+0
	clc
	adc #32
	sta <IRQ_SPLIT_LIST+0
	bcc :+
	inc <IRQ_SPLIT_LIST+1
:

	rts
	
	
irq_dungeon_push_list_1:

	.repeat 28,N
	lda _update_list+N,y
	sta PPU_DATA
	.endrepeat
		
	tya
	clc
	adc #28
	tay
	
	rts
	
irq_dungeon_push_list_2:

	.repeat 28,N
	lda _split_list+N,y
	sta PPU_DATA
	.endrepeat

	tya
	clc
	adc #28
	tay
	
	rts
	

irq_dungeon:

	sta MMC3_IRQ_DISABLE
	
	pha
	txa
	pha
	tya
	pha
	
	lda #0
	sta PPU_MASK

	lda #>DUNGEON_NT_ADR
	sta <IRQ_SPLIT_LIST+1
	lda #<DUNGEON_NT_ADR
	sta <IRQ_SPLIT_LIST+0

	ldy #0
	ldx #9
:

	jsr irq_dungeon_set_nt
	jsr irq_dungeon_push_list_1
	
	dex
	bne :-

	ldy #0
	ldx #9
:

	jsr irq_dungeon_set_nt
	jsr irq_dungeon_push_list_2
		
	dex
	bne :-
	
	pla
	tay
	pla
	tax
	pla
	
	rti
	
	
;------------------------------------------------------------------------------

irq_pacman_init:

	rts
	
irq_pacman:

	sta MMC3_IRQ_DISABLE
	
	pha
	txa
	pha
	tya
	pha
	
	lda #0
	sta PPU_MASK

	ldx #0
	
@loop:

	lda _split_list,x
	bmi @done
	
	sta PPU_ADDR
	inx
	lda _split_list,x
	sta PPU_ADDR
	inx
	lda _split_list,x
	sta PPU_DATA
	inx

	jmp @loop
	
@done:
	
	pla
	tay
	pla
	tax
	pla
	
	rti