;==========================================================================================
;
;   UNOFFICIAL SNES POWERPAK FIRMWARE V2.02 (CODENAME: "SIMBA")
;   (c) 2012/2013 by ManuLöwe (http://www.manuloewe.de/)
;
;	*** VIDEO SETUP & NMI HANDLER ***
;	Code in this file based on v1.0X code written by:
;	- bunnyboy (SNES PowerPak creator), (c) 2009
;	- Neviksti (subroutines ??), (c) 2002
;
;==========================================================================================



VBlank:
	rep #AXY_8BIT				; A/X/Y = 16 bit

	pha					; push 16 bit registers onto stack,
	phx					; so when it returns from the IRQ routine,
	phy					; it won't have screwed up anything

	phk					; set Data Bank = Program Bank
	plb

	sep #A_8BIT				; A = 8 bit

	jsr DoScrolling



; **************************** Move cursor *****************************

	lda cursorX
	sta SpriteBuf1
	lda cursorY
	sec
	sbc #$10
	; clc
	; adc #$08
	sta SpriteBuf1+1



; ************************** Refresh sprites ***************************

	stz $2102				; set OAM address to 0
	stz $2103

	; DMA parameters:
	; Mode: $00, CPU -> PPU, auto increment, write 1 byte
	; source bank: $00 (lower 8K of WRAM)
	; source offset: SpriteBuf1
	; B bus register: $2104 (OAM data write)
	; number of bytes to transfer: $0220 = 512 + 32 (OAM size)

	DMA_CH0 $00, $00, SpriteBuf1, $04, $0220



; **************************** Refresh BG2 *****************************

	LDA #$00				; VRAM address increment mode: increment address by one word
	STA $2115				; after accessing the low byte ($2118)

	LDX #$0400				; set VRAM address to BG2 tile map
	STX $2116

	; DMA parameters:
	; Mode: $00, CPU -> PPU, auto increment, write 1 byte
	; source bank: $7E (WRAM)
	; source offset: TxtBuf2bpp (computation result = lower 16 bit)
	; B bus register: $2118 (VRAM low byte)
	; number of bytes to transfer: $0400 = 1024 (tile map size)

	DMA_CH0 $00, $7E, (>TxtBuf2bpp)<<8+(<TxtBuf2bpp), $18, $0400



; **************************** Refresh BG1 *****************************

	LDA #$00				; VRAM address increment mode: increment address by one word
	STA $2115				; after accessing the low byte ($2118)

	LDX #$0800				; set VRAM address to BG1 tile map
	STX $2116

	; DMA parameters:
	; Mode: $00, CPU -> PPU, auto increment, write 1 byte
	; source bank: $7E (WRAM)
	; source offset: TxtBuf4bpp (computation result = lower 16 bit)
	; B bus register: $2118 (VRAM low byte)
	; number of bytes to transfer: $0400 = 1024 (tile map size)

	DMA_CH0 $00, $7E, (>TxtBuf4bpp)<<8+(<TxtBuf4bpp), $18, $0400



; ***************************** HDMA setup *****************************

	stz $420C				; turn off HDMA

	lda disableHDMA				; check for "emergency" off switch,
	bne __skipHDMA				; skip HDMA setup if value not zero

	jsr SetupHDMA				; set up HDMA transfers

	lda #%01100000				; activate HDMA channels 5 and 6
	sta $420C

__skipHDMA:



; ************************* Update joypad data *************************

	jsr GetInput



; ******************** Scrolling, misc., end Vblank ********************

	lda scrollY

	sta $210E				; BG1 vertical scroll
	stz $210E

	sta $2110				; BG2 vertical scroll
	stz $2110

	lda $4210				; clear NMI Flag

	rep #AXY_8BIT				; A/X/Y = 16 bit

	ply					; pull original 16 bit registers back
	plx
	pla
RTI



; ***************************** Set up GFX *****************************

QuickSetup:
	php

	rep #XY_8BIT				; A/mem = 8bit, X/Y=16bit
	sep #A_8BIT

	stz $2121				; start at color 0

	DMA_CH0 $00, :BG_Palette, BG_Palette, $22, $0200

	lda #$80				; VRAM address increment mode: increment address by one word
	sta $2115				; after accessing the high byte ($2119)

	ldx #$2000				; set VRAM address $2000 for BG2 font tiles
	stx $2116

	DMA_CH0 $01, :Font2bpp, Font2bpp, $18, $1000

	ldx #$4000				; set VRAM address $4000 for BG1 font tiles
	stx $2116

	DMA_CH0 $01, :Font4bpp, Font4bpp, $18, $2000

	ldx #$6000				; set VRAM address $6000 for sprite tiles
	stx $2116

	DMA_CH0 $01, :SpriteTiles, SpriteTiles, $18, $2000

	LDX #$0400				; set VRAM address $0400 for BG2 tilemap
	STX $2116

	LDX #$0400				; set BG2's tilemap size (32x32 tiles = 1024)
	LDA #$20				; set priority bit

__next_tile_BG2:
	STA $2119				; VRAM data write
	DEX
	BNE __next_tile_BG2

	LDX #$0800				; set VRAM address $0800 for BG1 tilemap
	STX $2116

	LDX #$0400				; set BG1's tilemap size (same as for BG2)
	LDA #$20				; set priority bit

__next_tile_BG1:
	STA $2119				; VRAM data write
	DEX
	BNE __next_tile_BG1



; ******************** Set up and enable the screen ********************

	lda #%01100011				; 16x16/32x32 sprites, character data at $6000 (word address)
	sta $2101

	lda #$05				; set BG mode 5 for horizontal high resolution
	sta $2105

;	lda #$08				; tell SETINI (Display Control 2) register, too (seems useless)
;	sta $2133

	lda #$08				; set BG1's Tile Map VRAM offset to $0800 (word address)
	sta $2107				; and the Tile Map size to 32 tiles x 32 tiles

	lda #$04				; set BG2's Tile Map VRAM offset to $0400 (word address)
	sta $2108				; and the Tile Map size to 32 tiles x 32 tiles

	lda #$24				; set BG1's Character VRAM offset to $4000 (word address)
	sta $210B				; and BG2's Character VRAM offset to $2000 (word address)

	lda #%00010011				; turn on BG1 + BG2 + sprites
	sta $212C				; on the mainscreen
	sta $212D				; and on the subscreen

	lda #%00100010				; enable window 1 on BG1 & BG2
	sta $2123				; (necessary to cut off scrolling "artifact" lines in the filebrowser)

	lda #$00				; set window 1 left position (0)
	sta $2126

	lda #$FF				; set window 1 right position (255), window fills the whole screen
	sta $2127

	lda #%00000011				; enable window masking (i.e., disable the content) on BG1 & BG2
	sta $212E				; on mainscreen
	sta $212F				; and subscreen (all window content is re-enabled via HDMA)

	lda #%00110000				; disable Color Math (see dev manual p. 2-19-1)
	sta $2130

	lda #$0F				; turn on the screen, full brightness
	sta $2100

	plp
rts



; ************************* Scrolling routines *************************

DoScrolling:
	lda cursorYCounter			; check cursor counter, no scroll if counter=0
	beq __CursorCheckDone

	dec cursorYCounter

	lda cursorY				; cursorY = cursorY - cursorYUp + cursorYDown
	sec
	sbc cursorYUp
	clc
	adc cursorYDown
	sta cursorY

__CursorCheckDone:

	lda scrollYCounter			; check scroll counter, no scroll if counter=0
	beq __DoYScrollDone
	dec scrollYCounter

	lda scrollY				; scroll = scroll - scrollUp + scrollDown
	sec
	sbc scrollYUp
	clc
	adc scrollYDown
	sta scrollY

__DoYScrollDone:

rts



ScrollUp:
	rep #A_8BIT				; A = 16 bit

	dec selectedEntry			; decrement entry index

	lda selectedEntry
	cmp #$FFFF				; check for underflow
	bne __ScrollUpCheckTop

	lda filesInDir				; underflow, set selectedEntry = filesInDir - 1
	dec a
	sta selectedEntry

	lda filesInDir				; check if filesInDir > maxFiles, which the cursor is restricted to, too
	cmp #maxFiles+1				; reminder: "+1" needed due to the way CMP affects the carry bit
	bcs __ScrollUpCheckTop

	sep #A_8BIT				; A = 8 bit

	lda filesInDir
	asl a
	asl a
	asl a					; multiply by 8 for sprite height
	clc
	adc #cursorYmin				; add Y indention
	sta cursorY				; put cursor at bottom of list

	bra __ScrollUpCheckMiddle

__ScrollUpCheckTop:
	sep #A_8BIT				; A = 8 bit

	lda cursorY
	cmp #cursorYmin				; check if cursor at top
	bne __ScrollUpCheckMiddle

	lda speedCounter
	sta scrollYCounter			; cursor at top, scroll background, leave cursor

	lda speedScroll
	sta scrollYUp

	stz scrollYDown

	lda insertTop
	sta temp

	jump jPrintClearLine

	lda temp
	asl a
	asl a
	asl a
	asl a
	asl a
	ora #minPrintX				; add horizontal indention
	sta Cursor

	lda temp
	lsr a
	lsr a
	lsr a
	sta Cursor+1

	jump jDirPrintEntry

	lda insertBottom
	sec
	sbc #$01
	and #%00011111
	sta insertBottom

	lda insertTop
	sec
	sbc #$01
	and #%00011111
	sta insertTop

	bra __ScrollUpDone

__ScrollUpCheckMiddle:
	lda speedCounter
	sta cursorYCounter

	lda speedScroll
	sta cursorYUp

	stz cursorYDown

__ScrollUpDone:

rts



ScrollDown:
	rep #A_8BIT				; A = 16 bit

	inc selectedEntry			; increment entry index

	lda selectedEntry			; check if selectedEntry = filesInDir
	cmp filesInDir
	bne __ScrollDownCheckBottom

	stz selectedEntry			; if yes, overflow --> reset selectedEntry

	lda filesInDir				; check if filesInDir > maxFiles
	cmp #maxFiles+1
	bcs __ScrollDownCheckBottom

	sep #A_8BIT				; A = 8 bit

	lda #cursorYmin-$08			; put cursor at top of screen
	sta cursorY				; (subtraction necessary because it "scrolls in" from one line above)

	bra __ScrollDownCheckMiddle

__ScrollDownCheckBottom:
	sep #A_8BIT				; A = 8 bit

	lda cursorY
	cmp #cursorYmax				; check if cursor at bottom
	bne __ScrollDownCheckMiddle

	lda speedCounter			; cursor at bottom, move background, leave cursor
	sta scrollYCounter			; set scrollYCounter (8 or 4)

	lda speedScroll
	sta scrollYDown				; set scrollYDown to speed (1 or 2)

	stz scrollYUp

	lda insertBottom
	sta temp

	jump jPrintClearLine

	lda temp
	asl a
	asl a
	asl a
	asl a
	asl a
	ora #minPrintX				; add horizontal indention
	sta Cursor

	lda temp
	lsr a
	lsr a
	lsr a
	sta Cursor+1

	jump jDirPrintEntry

	lda insertBottom
	clc
	adc #$01
	and #%00011111
	sta insertBottom

	lda insertTop
	clc
	adc #$01
	and #%00011111
	sta insertTop

	bra __ScrollDownDone

__ScrollDownCheckMiddle:
	lda speedCounter
	sta cursorYCounter

	lda speedScroll
	sta cursorYDown

	stz cursorYUp

__ScrollDownDone:

rts



; ************************** HDMA parameters ***************************

SetupHDMA:
	lda configBGdesign			; check for color user setting
	cmp #$01
	bne +
	ldx #HDMAColorGrad1			; "Ocean"
	stx $4352				; channel 5: background color gradient
	lda #:HDMAColorGrad1
	sta $4354
	bra __nextParameter
+
	cmp #$02
	bne +
	ldx #HDMAColorGrad2			; "Aero"
	stx $4352
	lda #:HDMAColorGrad2
	sta $4354
	bra __nextParameter
+
	cmp #$03
	bne +
	ldx #HDMAColorGrad3			; "Flare"
	stx $4352
	lda #:HDMAColorGrad3
	sta $4354
	bra __nextParameter
+
	cmp #$04
	bne +
	ldx #HDMAColorGrad4			; "Nova"
	stx $4352
	lda #:HDMAColorGrad4
	sta $4354
	bra __nextParameter
+
	cmp #$05
	bne +
	ldx #HDMAColorGrad5			; "Dune"
	stx $4352
	lda #:HDMAColorGrad5
	sta $4354
	bra __nextParameter
+
	cmp #$06
	bne +
	ldx #HDMAColorGrad6			; "Sky"
	stx $4352
	lda #:HDMAColorGrad6
	sta $4354
	bra __nextParameter
+
	ldx #HDMABlackBG			; black BG (for temporary purposes, e.g. while checking CF on startup)
	stx $4352
	lda #:HDMABlackBG
	sta $4354

__nextParameter:
	lda #$21				; PPU register $2121 (color index)
	sta $4351
	lda #$03				; transfer mode (4 bytes --> $2121, $2121, $2122, $2122)
	sta $4350

	ldx #HDMAWindow				; channel 6: mainscreen window
	stx $4362
	lda #:HDMAWindow
	sta $4364
	lda #$2E				; PPU reg. $212E (enable/disable mainscreen BG window area)
	sta $4361
	lda #$01				; transfer mode (2 bytes --> $212E, $212F)
	sta $4360
rts



; **************************** HDMA tables *****************************

	.INCLUDE "loader_hdmatables.inc"	; HDMA tables in separate file
