;==========================================================================================
;
;   UNOFFICIAL SNES POWERPAK FIRMWARE V2.01 (CODENAME: "SIMBA")
;   (c) 2012/2013 by ManuLöwe (http://www.manuloewe.de/)
;
;	*** MAIN BOOTLOADER CODE ***
;	Code in this file based on v1.0X code written by:
;	- bunnyboy (SNES PowerPak creator), (c) 2009
;
;==========================================================================================



LoadRomVersion:					; all preformatted for correct centering!
	ClearLine 9
;	SetCursorPos 9, 8
;	PrintString "Firmware vX.00-alphaX"
;	SetCursorPos 9, 8
;	PrintString " Firmware v2.00-betaX"
	SetCursorPos 9, 8
	PrintString "Firmware v2.01 \"SIMBA\""
rts



Main:

; ************************** Initialize SNES ***************************

	sei					; disable interrupts
	clc
	xce					; switch to native mode

	rep #$38				; mem/A = 16 bit, X/Y = 16 bit, decimal mode off

	ldx #$1FFF				; set up the stack
	txs

	jsl InitSNES				; continue initialization in separate routine

	sep #A_8BIT				; 8 bit Accumulator, 16 bit X/Y
	rep #XY_8BIT



; ************************** Build jump table **************************

	ldy #$0000

JumpTableLoop:
	lda JumpTableStart, y
	sta jumpTable, y
	iny
	cpy #$0080				; 128 bytes = 64 functions
	bne JumpTableLoop

	bra JumpTableEnd

JumpTableStart:					; add RAM jumptable
	.DW CardReadSector
	.DW CardWriteSector
	.DW Forever
	.DW CardReset
	.DW CardWaitNotBusy
	.DW CardWaitReady
	.DW CardWaitDataReq
	.DW CardCheckError
	.DW CardLoadLBA
	.DW CardReadBytesNoDMA
	.DW CardReadBytesToWRAM
	.DW CardReadBytesToFPGA
	.DW CardReadBytesToSDRAM
	.DW CardReadBytesToSDRAMNoDMA
	.DW CardReadFile
	.DW CardWriteFile
	.DW CardWriteBytesFromWRAM
	.DW CardWriteBytesFromSDRAM
	.DW CardLoadModule
	.DW CardLoadDirClearEntryName
	.DW CardLoadDir
	.DW ClusterToLBA
	.DW NextCluster
	.DW DirPrintDir
	.DW DirPrintEntry
	.DW DirGetEntry
	.DW DirFindEntry
	.DW NextDir
	.DW PrintF
	.DW PrintInt8_noload
	.DW PrintHex8_noload
	.DW PrintClearLine
	.DW PrintClearScreen
	.DW DoScrolling
	.DW ScrollUp
	.DW ScrollDown
	.DW LoadNextSectorNum
	.DW CardLoadFPGA
	.DW ClearFindEntry
	.DW GameGeniePrint
	.DW GameGenieClear
	.DW GameGenieDecode
	.DW GameGenieGetOffset
	.DW GameGenieNextChar
	.DW GameGeniePrevChar
	.DW GameGenieCharStore
	.DW GameGenieWriteCode
	.DW LoadLogo
	.DW LoadRomVersion
	.DW MemCheck
	.DW CopyROMInfo
	.DW CopyBanks
	.DW PrintBanks
	.DW LogScreen
	.DW SWCHeaderCheck
	.DW GD3HeaderCheck
	.DW WaitHblank				; 57 functions, max = 64

JumpTableEnd:



	jsr SpriteInit				; set up the sprite buffer

	sep #A_8BIT				; 8 bit Accumulator, 16 bit X/Y
	rep #XY_8BIT

	jsr QuickSetup				; set VRAM, video mode, background and character pointers,
						; and turn on the screen

	sep #A_8BIT				; 8 bit Accumulator, 16 bit X/Y
	rep #XY_8BIT

	jsr JoyInit				; initialize joypads and enable NMI

	sep #A_8BIT				; 8 bit Accumulator, 16 bit X/Y
	rep #XY_8BIT

	jump jLoadRomVersion

;  LDA #%10001111
;  STA $2100					; force VBlank, also setting brightness to 0



; ************************ Begin CF interaction ************************

	lda #$00				; clear out cluster info
	sta gameName.gCluster
	sta gameName.gCluster+1
	sta gameName.gCluster+2
	sta gameName.gCluster+3
	sta saveName.sCluster
	sta saveName.sCluster+1
	sta saveName.sCluster+2
	sta saveName.sCluster+3

	jump jCardReset

	wai



;For:
;  jmp For

;  ClearLine 5
;  ClearLine 6
;  ClearLine 7;
;  SetCursorPos 5, 1

;  lda CONFIGREADSTATUS   ;open bus = $20  want $Ax
;  sta errorCode;
;  PrintString "FPGA status="
;  PrintHexNum errorCode;
;  PrintString "\n"
 ; lda errorCode
 ; and #$F0
 ; cmp #$A0
 ; bne fpgaNOTconfigured

;fpgaISconfigured:
;  PrintString "fpgaISconfigured\n"
 ; jmp StateProgramFPGADone

;fpgaNOTconfigured:
;StateProgramFPGA:
;  PrintString "StateProgramFPGA\n"
 ; lda #$01
  ;;sta FPGAPROGRAMWRITE
  ;lda #$00
  ;sta FPGAPROGRAMWRITE   ;;SEND PROGRAM SIGNAL TO FPGA
  ;lda #$01
  ;sta FPGAPROGRAMWRITE

;;FPGA = $60D1 bytes
  ;ldy #$6100
  ;ldx #$0000
;StateProgramFPGALoop:
 ; lda.l TopLevel, x
 ; sta FPGADATAWRITE
 ; inx
 ; dey
 ; bne StateProgramFPGALoop
;  PrintString "StateProgramFPGADone\n"
;StateProgramFPGADone:



StateCardNotInserted:				; wait until card inserted, show no card message
	lda CARDSTATUS
	sta errorCode
	and #%11110000				; open bus = A0
	cmp #$A0
	beq StateCardNotInsertedLoop
	jmp StateCardNotInsertedDone

StateCardNotInsertedLoop:
	wai
	wai
	wai
	ClearLine 10
	SetCursorPos 10, 6
	PrintString "Error $"
	PrintHexNum errorCode
	PrintString " - CF card not found"

ShowConsoleVersion:
	lda $4210				; CPU revision
	and #$0F
	sta temp
	lda $213E				; PPU1 revision
	and #$0F
	sta temp+1
	lda $213F				; PPU2 revision
	and #$0F
	sta temp+2

	SetCursorPos 12,23			; print chipset revision
	PrintString "CPU: "
	PrintHexNum temp

	SetCursorPos 13,22
	PrintString " PPU1: "
	PrintHexNum temp+1

	SetCursorPos 14,22
	PrintString " PPU2: "
	PrintHexNum temp+2

	lda #$01				; switch to standard blue HDMA background,
	wai					; to be activated on next Vblank
	sta configBGdesign

	lda #$00				; logo tile difference ($00 = PowerPak, $7C = Simba, $84 = SFC dots)
	sta temp
;	lda #$00				; logo palette diff. ($00 = PowerPak, $02 = Simba, $04 = SFC dots)
	sta temp+1
;	lda #$00				; standard PowerPak cursor
	sta temp+2
	lda #$06				; standard PowerPak cursor palette
	sta temp+3

	jump jLoadLogo				; show logo



NoCard:
	jump jCardReset

	lda CARDSTATUS
	and #%11110000				; open bus = A0
	cmp #$A0
	beq NoCard

StateCardNotInsertedDone:
	ClearLine 12				; hide chipset revision
	ClearLine 13
	ClearLine 14



StateCardBusy:					; wait until card not busy, show card busy message
	lda CARDSTATUS
	sta errorCode
	and #%10000000
	cmp #%10000000				; busy = $80
	bne StateCardBusyDone
	wai
	ClearLine 10
	SetCursorPos 10, 7
	PrintString " Error $"
	PrintHexNum errorCode
	PrintString " - CF card busy"
	bra StateCardBusy

StateCardBusyDone:



StateCardReady:					; wait until card ready, show card not ready message
	lda CARDSTATUS
	sta errorCode
	and #%01010000
	cmp #%01010000				; ready = $50
	beq StateCardReadyDone
	wai
	ClearLine 10
	SetCursorPos 10, 6
	PrintString "Error $"
	PrintHexNum errorCode
	PrintString " - CF card not ready"
	bra StateCardReady

StateCardReadyDone:



	ClearLine 10
	SetCursorPos 10, 10
	PrintString "CF card booted"

	lda #$01				; not using DMA
	sta dontUseDMA

;	jsr Delay5Sec				; for debugging


;;;;
;; set some features
;  jump jCardWaitNotBusy
;  jump jCardWaitReady
;  jump jCardCheckError

;  SetCursorPos 12, 0
;  PrintString " card ready     "

;;select disk 0
;  lda #%00000000
;  sta CARDLBA3             ;select card 0

;  SetCursorPos 12, 0
;  PrintString " card 0 selected"

;; send feature = 01 - 8 bit transfers
;  lda #$01
;  sta CARDERROR
;  lda #$EF
;  sta CARDCOMMAND

;  SetCursorPos 12, 0
;  PrintString " feature written"

;  jump jCardCheckError



;  lda #$10
;  sta temp+5      ;;try copying 16 times
;StateCardBooted:
;  lda temp+5
;  sta temp+6
;StateCardBootedWait:
;  dec temp+6
;  bne StateCardBootedWait  ;;try to shift by some clocks
;  stz sourceSector
;  stz sourceSector+1
;  stz sourceSector+2
;  stz sourceSector+3
;  lda #<sectorBuffer1
;  sta destLo
;  lda #>sectorBuffer1
;  sta destHi
;  stz destBank
;  lda #kDestWRAM
;  sta destType
;  stz sectorBuffer1+$1FE
;  stz sectorBuffer1+$1FF
;  jump jCardReadSector      ;read sector 0 to internal ram
;  lda sectorBuffer1+$1FE
;  cmp #$55
;  bne DMAError              ;last word check  should be $55AA
;  lda sectorBuffer1+$1FF
;  cmp #$AA
;  bne DMAError              ;last word check  should be $55AA
;  dec temp+5
;  bne StateCardBooted
;  jmp CardFormatCheck
;DMAError:
;  lda #$01
;  sta dontUseDMA
;  ClearLine 3
;  SetCursorPos 3, 1
;  PrintString "DMA OFF\n"



	stz sourceSector
	stz sourceSector+1
	stz sourceSector+2
	stz sourceSector+3
	lda #<sectorBuffer1
	sta destLo
	lda #>sectorBuffer1
	sta destHi
	lda #$00
	sta destBank
	lda #kDestWRAM				; try with DMA on
	sta destType

	jump jCardReadSector			; read sector 0 to internal RAM

	lda sectorBuffer1+$1FE			; last word check, should be $55AA
	cmp #$55
	beq CardFormatCheck			; ### FIXME

; jmp CardFormatError

CardFormatCheck:
	lda sectorBuffer1+$1FF
	cmp #$AA
	bne CardFormatErrorJump

	ldy #$0000				; y = partition number  0-3
	ldx #$0000				; x = partition index   0, 16, 32, 48

CardFormatCheckLoop:
	lda #$01
	sta fat32Enabled
	lda sectorBuffer1+$1C2, x		; format  fat32 = 0x0B   FAT32
	cmp #$0B
	beq CardGoodFormat
	lda sectorBuffer1+$1C2, x		; format  fat32 = 0x0C   FAT32 LBA
	cmp #$0C
	beq CardGoodFormat

	lda #$00
	sta fat32Enabled
	lda sectorBuffer1+$1C2, x		; format  fat16 = 0x06  larger than 32MB
	cmp #$06
	beq CardGoodFormat
	lda sectorBuffer1+$1C2, x		; format  fat16 = 0x04  smaller than 32MB
	cmp #$04
	beq CardGoodFormat
	lda sectorBuffer1+$1C2, x		; format  fat16 = 0x0E  with LBA
	cmp #$0E
	beq CardGoodFormat

	inx
	inx
	inx
	inx

	inx
	inx
	inx
	inx

	inx
	inx
	inx
	inx

	inx
	inx
	inx
	inx

	iny
	cpy #$0004
	bne CardFormatCheckLoop

CardFormatErrorJump:
	jmp CardFormatError



CardGoodFormat:					; FAT32/FAT16 partition found
	stx partitionIndex

	ClearLine 10
	SetCursorPos 10, 10
	PrintString "FAT32/16 found"

;	jsr Delay5Sec				; for debugging

	ldx partitionIndex
	ldy #$0000

CardCopyPartitionLBABegin:			; copy partitionLBABegin from offset 455
	lda sectorBuffer1+$1C6, x
	sta sourceSector, y
	sta partitionLBABegin, y
	inx
	iny
	cpy #$0004
	bne CardCopyPartitionLBABegin

	lda #<sectorBuffer1
	sta destLo
	lda #>sectorBuffer1
	sta destHi
	stz destBank
	lda #kDestWRAM
	sta destType

	jump jCardReadSector			; read FAT16/FAT32 Volume ID sector  (partition boot record)

	lda sectorBuffer1+$0D			; copy FAT16/FAT32 sectorsPerCluster from offset 13
	sta sectorsPerCluster

	lda sectorBuffer1+$0E			; copy FAT16/FAT32 reservedSectors from offset 14
	sta reservedSectors
	lda sectorBuffer1+$0F
	sta reservedSectors+1

	ldx #$0000

CardCopySectorsPerFat:				; copy FAT32 sectorsPerFat from offset 36
	lda sectorBuffer1+$24, x
	sta sectorsPerFat, x
	inx
	cpx #$0004
	bne CardCopySectorsPerFat

	ldx #$0000

CardCopyRootDirCluster32:			; copy FAT32 rootDirCluster from offset 44
	lda sectorBuffer1+$2C, x
	sta rootDirCluster, x
	inx
	cpx #$0004
	bne CardCopyRootDirCluster32

	lda #$00
	sta fat16RootSectors			; FAT32 no entry limit in root directory

	lda fat32Enabled
	cmp #$01
	beq CardCopyFatBeginLBA			; when FAT32, leave alone



;;;SPECIAL FAT16 handling

CardCopyRootDirCluster16:
	stz rootDirCluster
	stz rootDirCluster+1			; when FAT16, rootDirCluster = 0000 (root dir is not in cluster nums)
	stz rootDirCluster+2
	stz rootDirCluster+3

	lda sectorBuffer1+$16
	sta sectorsPerFat			; FAT16 copy sectorsPerFat from offset 22
	lda sectorBuffer1+$17
	sta sectorsPerFat+1
	stz sectorsPerFat+2
	stz sectorsPerFat+3			; FAT16 sectors per fat = 16 bits, in different place than FAT32


CardCopyRootDirEntries16:			; copy max root directory entries from offset 17
	lda sectorBuffer1+$11
	sta fat16RootSectors
	lda sectorBuffer1+$12
	sta fat16RootSectors+1

;  clc
;  lsr fat16RootSectors
;  lsr fat16RootSectors           ; FAT16 rootSectors =  (max root entries * 32) / 512   =   fat16RootSectors/16  ASR x4
;  lsr fat16RootSectors
;  lsr fat16RootSectors

	lda #$20
	sta fat16RootSectors			; FAT16 root dir fixed at 512 entries = 32 sectors



CardCopyFatBeginLBA:
	clc					; fatBeginLBA(4) = partitionLBABegin(4) + reservedSectors(2)
	lda reservedSectors
	adc partitionLBABegin
	sta fatBeginLBA
	lda reservedSectors+1
	adc partitionLBABegin+1
	sta fatBeginLBA+1
	lda partitionLBABegin+2
	adc #$00
	sta fatBeginLBA+2
	lda partitionLBABegin+3
	adc #$00
	sta fatBeginLBA+3

CardCopyClusterBeginLBA:
	lda sectorsPerFat
	sta clusterBeginLBA
	lda sectorsPerFat+1
	sta clusterBeginLBA+1
	lda sectorsPerFat+2
	sta clusterBeginLBA+2
	lda sectorsPerFat+3
	sta clusterBeginLBA+3

	clc
	asl clusterBeginLBA			; clusterBeginLBA(4) = fatBeginLBA(4) + (2 * sectorPerFat(4))
	rol clusterBeginLBA+1
	rol clusterBeginLBA+2
	rol clusterBeginLBA+3

	clc					; FAT16 = 32 sectors       FAT32 = 0 sectors
	lda clusterBeginLBA			; clusterBeginLBA(4) = clusterBeginLBA(4) + fat16RootSectors(1)
	adc fat16RootSectors
	sta clusterBeginLBA
	lda clusterBeginLBA+1
	adc #$00
	sta clusterBeginLBA+1
	lda clusterBeginLBA+2
	adc #$00
	sta clusterBeginLBA+2
	lda clusterBeginLBA+3
	adc #$00
	sta clusterBeginLBA+3

	clc
	lda clusterBeginLBA
	adc fatBeginLBA
	sta clusterBeginLBA
	lda clusterBeginLBA+1
	adc fatBeginLBA+1
	sta clusterBeginLBA+1
	lda clusterBeginLBA+2
	adc fatBeginLBA+2
	sta clusterBeginLBA+2
	lda clusterBeginLBA+3
	adc fatBeginLBA+3
	sta clusterBeginLBA+3

	lda rootDirCluster
	sta sourceCluster
	lda rootDirCluster+1
	sta sourceCluster+1
	lda rootDirCluster+2
	sta sourceCluster+2
	lda rootDirCluster+3
	sta sourceCluster+3

 ; PrintString "\n"
 ; PrintHexNum sectorsPerCluster
 ; PrintString "\n"



.ifdef DEBUG
	PrintString "fat16 != "
	PrintHexNum fat32Enabled
	PrintString "  RootSectors $"
	PrintHexNum fat16RootSectors
	PrintString "\n"

	PrintString "sectorsPerFat $"
	PrintHexNum sectorsPerFat+3
	PrintHexNum sectorsPerFat+2
	PrintHexNum sectorsPerFat+1
	PrintHexNum sectorsPerFat+0
	PrintString "\n"

	PrintString "partitionLBABegin $"
	PrintHexNum partitionLBABegin+3
	PrintHexNum partitionLBABegin+2
	PrintHexNum partitionLBABegin+1
	PrintHexNum partitionLBABegin+0
	PrintString "\n"

	PrintString "reservedSectors $"
	PrintHexNum reservedSectors+1
	PrintHexNum reservedSectors+0
	PrintString "\n"

	PrintString "fatBeginLBA $"
	PrintHexNum fatBeginLBA+3
	PrintHexNum fatBeginLBA+2
	PrintHexNum fatBeginLBA+1
	PrintHexNum fatBeginLBA+0
	PrintString "\n"

	PrintString "rootDirCluster $"
	PrintHexNum rootDirCluster+3
	PrintHexNum rootDirCluster+2
	PrintHexNum rootDirCluster+1
	PrintHexNum rootDirCluster+0
	PrintString "\n"
.endif



; ************************* Load Configuration *************************

	jump jCardLoadDir			; root dir

	lda #'P'
	sta findEntry
	lda #'O'
	sta findEntry+1
	lda #'W'
	sta findEntry+2
	lda #'E'
	sta findEntry+3
	lda #'R'
	sta findEntry+4
	lda #'P'
	sta findEntry+5
	lda #'A'
	sta findEntry+6
	lda #'K'
	sta findEntry+7

	jump jDirFindEntry			; "POWERPAK" dir into tempEntry

	lda tempEntry.tempCluster
	sta baseDirCluster
	lda tempEntry.tempCluster+1
	sta baseDirCluster+1
	lda tempEntry.tempCluster+2
	sta baseDirCluster+2
	lda tempEntry.tempCluster+3
	sta baseDirCluster+3			; "POWERPAK" dir found, write base cluster



.ifdef DEBUG
	PrintString "baseDirCluster $"
	PrintHexNum baseDirCluster+3
	PrintHexNum baseDirCluster+2
	PrintHexNum baseDirCluster+1
	PrintHexNum baseDirCluster+0
	PrintString "\n"
.endif



LoadConfig:
	FindFile "CONFIG.TXT"

	lda #<sectorBuffer1
	sta destLo
	lda #>sectorBuffer1
	sta destHi				; put into sector RAM
	stz destBank
	stz sectorCounter
	stz bankCounter

	jump jClusterToLBA			; sourceCluster -> first sourceSector

	lda #kDestWRAM
	sta destType

	jump jCardReadSector			; sector -> WRAM

	ldy #$0000

LoadDMAConfigLoop:				; look for DMA=0 / DMA=1
	lda sectorBuffer1, y
	cmp #'D'
	beq LoadDMAConfigLoopFound

LoadDMAConfigLoopNext:
	iny
	cpy #$0200				; changed to 512 bytes
	bne LoadDMAConfigLoop

	bra __DMAStandard			; in case DMA=X entry isn't found, load standard setting below

LoadDMAConfigLoopFound:
	iny
	lda sectorBuffer1, y
	cmp #'M'
	bne LoadDMAConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'A'
	bne LoadDMAConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'='
	bne LoadDMAConfigLoopNext

LoadDMAConfigLoopRecord:
	iny
	lda sectorBuffer1, y
	cmp #'0'
	bne __DMAStandard
	lda #$00				; if DMA=0, write $00 into configuration buffer
	sta configDMA
	bra LoadDMAConfigDone

__DMAStandard:
	lda #$01				; ... and $01 in any other case (switch DMA on)
	sta configDMA
	lda #$00				; tell DMA "blocker" variable, too (not needed above with
	sta dontUseDMA				; DMA=0 since DMA is initially off anyway!)

LoadDMAConfigDone:



	ldy #$0000

UserLogoConfigLoop:				; look for LOGO=1 / LOGO=2 / LOGO=3
	lda sectorBuffer1, y
	cmp #'L'
	beq UserLogoConfigLoopFound

UserLogoConfigLoopNext:
	iny
	cpy #$0200
	bne UserLogoConfigLoop

	bra __LogoStandard			; in case LOGO=X entry isn't found, load standard logo below

UserLogoConfigLoopFound:
	iny
	lda sectorBuffer1, y
	cmp #'O'
	bne UserLogoConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'G'
	bne UserLogoConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'O'
	bne UserLogoConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'='
	bne UserLogoConfigLoopNext

UserLogoConfigLoopRecord:
	iny
	lda sectorBuffer1, y
	cmp #'2'				; if LOGO=2, write $02 into configuration buffer
	bne +
	lda #$02
	bra UserLogoConfigDone
+
	cmp #'3'				; if LOGO=3, write $03 into configuration buffer
	bne __LogoStandard
	lda #$03
	bra UserLogoConfigDone

__LogoStandard:
	lda #$01				; in any other case, $01 (standard PowerPak logo)

UserLogoConfigDone:
	sta configLogo



	ldy #$0000

BGDesignConfigLoop:				; look for BGDESIGN=1...6
	lda sectorBuffer1, y
	cmp #'B'
	beq BGDesignConfigLoopFound

BGDesignConfigLoopNext:
	iny
	cpy #$0200
	bne BGDesignConfigLoop

	bra __BGDesignStandard			; in case BGDESIGN=X entry isn't found, load standard design below

BGDesignConfigLoopFound:
	iny
	lda sectorBuffer1, y
	cmp #'G'
	bne BGDesignConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'D'
	bne BGDesignConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'E'
	bne BGDesignConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'S'
	bne BGDesignConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'I'
	bne BGDesignConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'G'
	bne BGDesignConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'N'
	bne BGDesignConfigLoopNext
	iny
	lda sectorBuffer1, y
	cmp #'='
	bne BGDesignConfigLoopNext

BGDesignConfigLoopRecord:
	iny
	lda sectorBuffer1, y
	cmp #'2'				; if BGDESIGN=2...6, write $02...$06 into configuration buffer
	bne +
	lda #$02
	bra BGDesignConfigDone
+
	cmp #'3'
	bne +
	lda #$03
	bra BGDesignConfigDone
+
	cmp #'4'
	bne +
	lda #$04
	bra BGDesignConfigDone
+
	cmp #'5'
	bne +
	lda #$05
	bra BGDesignConfigDone
+
	cmp #'6'
	bne __BGDesignStandard
	lda #$06
	bra BGDesignConfigDone

__BGDesignStandard:				; in any other case, $01 ("Ocean" BG design)
	lda #$01

BGDesignConfigDone:
	wai
	sta configBGdesign



; ************************* Load intro & logo **************************

LoaderLoadModuleDone:
	wai

	FindFile "SI.MAP"

	jump jCardLoadModule			; load intro module



Forever:
	lda #$81
	sta $4200				; turn on NMI

ForeverLoop:
	wai					; wait for next frame
	bra ForeverLoop



LoadLogo:
	lda #$5A				; X
	sta SpriteBuf1+16
	lda #$10				; Y
	sta SpriteBuf1+17
	lda #$04				; tile num
	clc
	adc temp				; plus diff, depending on user setting
	sta SpriteBuf1+18
	lda #$00				; vhoopppc Vert Horiz priOrity Palette Charmsb
	clc
	adc temp+1				; plus palette diff, depending on user setting
	sta SpriteBuf1+19

	lda #$7A				; X
	sta SpriteBuf1+20
	lda #$10				; Y
	sta SpriteBuf1+21
	lda #$08				; tile num
	clc
	adc temp				; plus diff, depending on user setting
	sta SpriteBuf1+22
	lda #$00				; vhoopppc Vert Horiz priOrity Palette Charmsb
	clc
	adc temp+1				; plus palette diff, depending on user setting
	sta SpriteBuf1+23

	lda #$5A				; X
	sta SpriteBuf1+24
	lda #$30				; Y
	sta SpriteBuf1+25
	lda #$44				; tile num
	clc
	adc temp				; plus diff, depending on user setting
	sta SpriteBuf1+26
	lda #$00				; vhoopppc Vert Horiz priOrity Palette Charmsb
	clc
	adc temp+1				; plus palette diff, depending on user setting
	sta SpriteBuf1+27

	lda #$7A				; X
	sta SpriteBuf1+28
	lda #$30				; Y
	sta SpriteBuf1+29
	lda #$48				; tile num
	clc
	adc temp				; plus diff, depending on user setting
	sta SpriteBuf1+30
	lda #$00				; vhoopppc Vert Horiz priOrity Palette Charmsb
	clc
	adc temp+1				; plus palette diff, depending on user setting
	sta SpriteBuf1+31

	lda #$AA
	sta SpriteBuf2+1			; 32x32 sprites

	lda temp+2				; tile num for cursor, next is palette
	sta SpriteBuf1+2
	lda temp+3				; vhoopppc Vert Horiz priOrity Palette Charmsb
	sta SpriteBuf1+3

	SetCursorPos 7, 7
	PrintString "S N E S    P O W E R P A K"
rts



; ************************* CF error handling **************************

CardFormatError:
	ClearLine 19
	ClearLine 20
	ClearLine 21
	SetCursorPos 19, 1
	PrintString "Card format error:"
	PrintString "\n  FAT32 or FAT16 expected!"
	PrintString "\n  1C2(fm)="
	lda sectorBuffer1+$1C2			; card last word read
	sta errorCode
	PrintHexNum errorCode
	PrintString " 1FE(55)="
	lda sectorBuffer1+$1FE			; card last word read
	sta errorCode
	PrintHexNum errorCode
	PrintString " 1FF(AA)="
	lda sectorBuffer1+$1FF			; card last word read
	sta errorCode
	PrintHexNum errorCode

	jump jForever



CardReset:
	lda #%00000000
	sta CARDLBA3				; select card 0

	lda #%00000110				; do card sw reset
	sta CARDDEVICE				; in device ctl reg
	wai
	wai
	lda #%00000010
	sta CARDDEVICE				; clear reset
	wai
	wai
rts



CardWaitNotBusy:

CardWaitNotBusyLoop:				; wait for not busy
	lda CARDSTATUS				; card status read
	sta errorCode
	and #%10000000
	cmp #%10000000				; check busy bit
	bne CardWaitNotBusyDone
;  SetCursorPos 12, 0
;  PrintString "    Error $"
;  PrintHexNum errorCode
;  PrintString " - CF card busy    "
	bra CardWaitNotBusyLoop

CardWaitNotBusyDone:

rts



CardWaitReady:

CardWaitReadyLoop:				; wait until card ready
	lda CARDSTATUS
	sta errorCode
	and #%01010000
	cmp #%01010000
	beq CardWaitReadyDone
;  SetCursorPos 12, 0
;  PrintString "    Error $"
;  PrintHexNum errorCode
;  PrintString " - CF not ready    "
	bra CardWaitReadyLoop

CardWaitReadyDone:

rts



CardWaitDataReq:				; wait for not busy, ready, datareq, no error

CardWaitDataReqLoop:
	lda CARDSTATUS
	sta errorCode
	and #%01011000
	cmp #%01011000
	beq CardWaitDataReqDone
;  SetCursorPos 12, 0
;  PrintString "    Error $"
;  PrintHexNum errorCode
;  PrintString " - CF no data req    "
	bra CardWaitDataReqLoop

CardWaitDataReqDone:

rts



CardCheckError:
	lda CARDSTATUS				; get card status, check for general error
	sta errorCode
	and #%00000001
	cmp #%00000001
	beq CardError
rts

CardError:
	ClearLine 19
	ClearLine 20
	SetCursorPos 19, 1
	PrintString "Error $"
	PrintHexNum errorCode
	PrintString " - CF card status"
	SetCursorPos 20, 1
	lda CARDERROR
	sta errorCode
	PrintString "Error $"
	PrintHexNum errorCode
	PrintString " - CF card error"

;.IFDEF DEBUG
	lda CARDSECTORCOUNTREAD
	sta errorCode
	PrintString "\n  c=$"
	PrintHexNum errorCode

	lda CARDLBA0READ
	sta errorCode
	PrintString " 0=$"
	PrintHexNum errorCode

	lda CARDLBA1READ
	sta errorCode
	PrintString " 1=$"
	PrintHexNum errorCode

	lda CARDLBA2READ
	sta errorCode
	PrintString " 2=$"
	PrintHexNum errorCode

	lda CARDLBA3READ
	sta errorCode
	PrintString " 3=$"
	PrintHexNum errorCode
	PrintString "\n"
;.ENDIF

CardErrorForever:
	jump jForever



CardLoadLBA:
	jump jCardWaitNotBusy
	jump jCardWaitReady
	jump jCardCheckError

	lda #$01
	sta CARDSECTORCOUNT
	jump jCardWaitNotBusy			; LAST check busy/ready/error after each command
	jump jCardWaitReady
; jump jCardCheckError

	lda sourceSector
	sta CARDLBA0
	jump jCardWaitNotBusy
	jump jCardWaitReady
; jump jCardCheckError

	lda sourceSector+1
	sta CARDLBA1
	jump jCardWaitNotBusy
	jump jCardWaitReady
; jump jCardCheckError

	lda sourceSector+2
	sta CARDLBA2
	jump jCardWaitNotBusy
	jump jCardWaitReady
; jump jCardCheckError

	lda sourceSector+3			; load LBA number
	and #%00001111
	ora #%11100000
	sta sourceSector+3
	sta CARDLBA3
	jump jCardWaitNotBusy
	jump jCardWaitReady
	jump jCardCheckError

rts



; ************************* Read from CF card **************************

CardReadSector:
	lda #$00
	sta $4200				; turn OFF NMI

	jump jCardLoadLBA

	lda #$00
	sta sourceBytes16
	lda #$02
	sta sourceBytes16+1

; jump jCardWaitNotBusy
; jump jCardWaitReady
; jump jCardCheckError

	lda #$20
	sta CARDCOMMAND				; send card read sector command

	jump jCardWaitNotBusy
	jump jCardWaitReady
	jump jCardCheckError

	jump jCardWaitDataReq



CardReadSectorToWRAM:				; CF to WRAM
	lda destType
	cmp #kDestWRAM
	bne CardReadSectorToWRAMDone

	lda dontUseDMA
	beq CardReadSectorToWRAMJump		; if dontUseDMA=1, no DMA
	jump jCardReadBytesNoDMA
	bra CardReadSectorCheckDone

CardReadSectorToWRAMJump:
	jump jCardReadBytesToWRAM		; CF to WRAM - DMA
	bra CardReadSectorCheckDone

CardReadSectorToWRAMDone:

CardReadSectorToFPGA:				; CF to FPGA - can't use DMA
	lda destType
	cmp #kDestFPGA
	bne CardReadSectorToFPGADone
	jump jCardReadBytesToFPGA
	bra CardReadSectorCheckDone

CardReadSectorToFPGADone:

CardReadSectorToSDRAM:				; CF to SDRAM - DMA, no inc
	lda destType
	cmp #kDestSDRAM
	bne CardReadSectorToSDRAMDone
	jump jCardReadBytesToSDRAM
	bra CardReadSectorCheckDone

CardReadSectorToSDRAMDone:


CardReadSectorToSDRAMNoDMA:			; CF to SDRAM - no DMA
	lda destType
	cmp #kDestSDRAMNoDMA
	bne CardReadSectorToSDRAMNoDMADone
	jump jCardReadBytesToSDRAMNoDMA
	bra CardReadSectorCheckDone

CardReadSectorToSDRAMNoDMADone:

	jump jCardReadBytesNoDMA		; CF to somewhere, no DMA

CardReadSectorCheckDone:



	jump jCardWaitNotBusy
	jump jCardWaitReady
	jump jCardCheckError

; lda CARDSECTORCOUNTREAD
; sta errorCode
; bne CardReadSectorFailed			; LAST make sure sectors = 0



CardReadSectorPassed:
; jump jCardWaitNotBusy			; LAST check for busy before error
; jump jCardWaitReady
; jump jCardCheckError
	lda $4210				; clear NMI Flag
	lda #$81
	sta $4200				; turn ON NMI

CardReadSectorDone:

rts



CardReadSectorFailed:
	ClearLine 19
	ClearLine 20
	SetCursorPos 19, 1
	PrintString "Error CF sectors left = "
	PrintHexNum errorCode
	SetCursorPos 20, 1
	lda CARDERROR
	sta errorCode
	PrintString "Error $"
	PrintHexNum errorCode
	PrintString " - CF card error"

CardReadSectorFailedForever:
	jump jForever



CardReadBytesNoDMA:				; read source256*sourceBytes bytes into RAM
	ldx sourceBytes16
	ldy #$0000

CardReadBytesNoDMALoop:
	lda CARDDATAREAD
; sta $000200, y
	sta [destLo], y
	iny
	dex
	bne CardReadBytesNoDMALoop
; PrintHexNum bankCounter
; PrintString "CardReadBytesDone\n"

rts



CardReadBytesToFPGA:				; no DMA
	ldx sourceBytes16

CardReadBytesToFPGALoop:
	lda CARDDATAREAD			; READ DATA BYTE
	sta FPGADATAWRITE			; WRITE TO FPGA
	dex
	bne CardReadBytesToFPGALoop
rts



CardReadBytesToWRAM:				; use DMA, no increment source or dest
	ldx destLo				; reminder: X is 16 bit, so this writes to both $2181 and $2182!
	stx $2181

	lda #$00				; load the RAM dest address
	sta $2183

	DMA_WaitHblank $08, CARDDATAREADbank, CARDDATAREADhigh, CARDDATAREADlow, $80, sourceBytes16
rts



CardReadBytesToSDRAMNoDMA:
	ldx sourceBytes16

CardReadBytesToSDRAMLoop:
	lda CARDDATAREAD			; READ DATA BYTE
	sta $0021FF				; WRITE TO SDRAM   //   SEE IF A021FF WORKS
	dex
	bne CardReadBytesToSDRAMLoop
rts



;;TEST THIS ONE
CardReadBytesToSDRAM:
	DMA_WaitHblank $08, CARDDATAREADbank, CARDDATAREADhigh, CARDDATAREADlow, $FF, sourceBytes16
rts



LoadNextSectorNumDebug:				; get next sector, use sectorCounter to check if next cluster needed
	clc
	lda sourceSector
	adc #$01
	sta sourceSector			; go to next sector num
	lda sourceSector+1
	adc #$00
	sta sourceSector+1
	lda sourceSector+2
	adc #$00
	sta sourceSector+2
	lda sourceSector+3
	adc #$00
	sta sourceSector+3

	clc
	lda sectorCounter			; one more sector
	adc #$01
	sta sectorCounter
	cmp sectorsPerCluster
	beq LoadNextClusterNumDebug
rts

LoadNextClusterNumDebug:
	lda #$00
	sta sectorCounter
	jump jNextCluster			; get cluster num into sourceCluster from FAT table

;  PrintString "cluster="
;  PrintString sourceCluster+3
;  PrintString sourceCluster+2
;  PrintString sourceCluster+1
;  PrintString sourceCluster+0
;  PrintString "\n"

	jump jClusterToLBA			; get sector num into sourceSector

;  PrintString "sector="
;  PrintHexNum sourceSector+3
;  PrintHexNum sourceSector+2
;  PrintHexNum sourceSector+1
;  PrintHexNum sourceSector+0
;  PrintString "\n"

;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai
;  wai

rts



CardReadFile:					; sourceCluster already set
	lda #$00
	sta gameSize
	sta gameSize+1

	jump jClusterToLBA			; sourceCluster -> first sourceSector

CardReadFileLoop:
;  PrintHexNum sourceSector+3
;  PrintHexNum sourceSector+2
;  PrintHexNum sourceSector+1
;  PrintHexNum sourceSector+0
;  PrintString "."
	clc
	lda gameSize
	adc #$01
	sta gameSize
	lda gameSize+1
	adc #$00
	sta gameSize+1				; keep track of game size

	lda #kDestSDRAM
	sta destType

	jump jCardReadSector

	lda destHi
	pha
	lda destLo
	pha
	jsr LoadNextSectorNumDebug
	pla
	sta destLo
	pla
	sta destHi

CardReadFileLastSectorCheck:
	lda #$0F
	sta temp
	lda #$FF
	sta temp+1				; FAT32 last cluster = 0x0FFFFFFF
	sta temp+2
	sta temp+3

	lda fat32Enabled
	cmp #$01
	beq CardReadFileLastSectorCheck2	; if FAT32, last cluster mask done

	lda #$00
	sta temp
	sta temp+1				; FAT16 last cluster = 0x0000FFFF

CardReadFileLastSectorCheck2:			; if cluster = last cluster, jump to last entry found
	lda temp
	cmp sourceCluster+3
	bne CardReadFileNextSector
	lda temp+1
	cmp sourceCluster+2
	bne CardReadFileNextSector
	lda temp+2
	cmp sourceCluster+1
	bne CardReadFileNextSector
	lda temp+3
	cmp sourceCluster+0
	bne CardReadFileNextSector
	bra CardReadFileDone

CardReadFileNextSector:
	inc destHi
	inc destHi
	inc bankCounter
	lda bankCounter
; cmp #$00                 ;;only load 256x512=128KB for modules
; beq CardReadFileDone

	bra CardReadFileLoop

CardReadFileDone:
rts



CardWriteFile:					; sourceCluster already set
	stz sectorCounter
	stz bankCounter
	lda #kDestWRAM
	sta destType

	jump jClusterToLBA			; sourceCluster -> first sourceSector

CardWriteFileLoop:
	jump jCardWriteSector			; sector -> code ram

	lda destHi
	pha
	lda destLo
	pha

	jump jLoadNextSectorNum

	pla
	sta destLo
	pla
	sta destHi

CardWriteFileLastSectorCheck:
	lda #$0F
	sta temp
	lda #$FF
	sta temp+1				; FAT32 last cluster = 0x0FFFFFFF
	sta temp+2
	sta temp+3

	lda fat32Enabled
	cmp #$01
	beq CardWriteFileLastSectorCheck2	; if FAT32, last cluster mask done

	lda #$00
	sta temp
	sta temp+1				; FAT16 last cluster = 0x0000FFFF

CardWriteFileLastSectorCheck2:			; if cluster = last cluster, jump to last entry found
	lda temp
	cmp sourceCluster+3
	bne CardWriteFileNextSector
	lda temp+1
	cmp sourceCluster+2
	bne CardWriteFileNextSector
	lda temp+2
	cmp sourceCluster+1
	bne CardWriteFileNextSector
	lda temp+3
	cmp sourceCluster+0
	bne CardWriteFileNextSector
	bra CardWriteFileDone

CardWriteFileNextSector:
	inc sourceHi
	inc sourceHi
	inc bankCounter
; lda bankCounter
; cmp #$00                 ;;only load 256x512=128KB for modules
; beq CardWriteFileDone
	bra CardWriteFileLoop

CardWriteFileDone:

rts



CardWriteSector:
	jump jCardWaitNotBusy
	jump jCardWaitReady
	jump jCardCheckError
	jump jCardLoadLBA

	lda #$00
	sta sourceBytes16
	lda #$02
	sta sourceBytes16+1

	jump jCardWaitNotBusy
	jump jCardWaitReady
	jump jCardCheckError

	lda #$30
	sta CARDCOMMAND				; send card write sector command
	nop
	nop

	jump jCardCheckError
	jump jCardWaitDataReq

CardWriteSectorSDRAM:
	lda sourceType
	cmp #kSourceSDRAM
	bne CardWriteSectorNotSDRAM

	jump jCardWriteBytesFromSDRAM

CardWriteSectorNotSDRAM:

CardWriteSectorWRAM:
	lda sourceType
	cmp #kSourceWRAM
	bne CardWriteSectorNotWRAM

	jump jCardWriteBytesFromWRAM

CardWriteSectorNotWRAM:
	jump jCardCheckError

CardWriteSectorDone:

rts



CardWriteBytesFromWRAM:				; write source256*sourceBytes bytes into CF card
	ldx sourceBytes16
	ldy #$0000

CardWriteBytesWRAMLoop:
	lda [sourceLo], y
	sta CARDDATAWRITE
	iny
	dex
	bne CardWriteBytesWRAMLoop
rts


CardWriteBytesFromSDRAM:			; write source256*sourceBytes bytes into CF card
	ldx sourceBytes16

CardWriteBytesSDRAMLoop:
	lda DMAREADDATA
	sta CARDDATAWRITE			; FIXME CHANGE TO USE DMA FROM SDRAM TO CF
	dex
	bne CardWriteBytesSDRAMLoop
rts



; cluster->lba     lba_addr(4) = clusterBeginLBA(4) + (cluster_number(2)-2 * sectorsPerCluster(1))
ClusterToLBA:
	sec
	lda sourceCluster
	sbc #$02
	sta sourceSector
	lda sourceCluster+1
	sbc #$00
	sta sourceSector+1
	lda sourceCluster+2
	sbc #$00
	sta sourceSector+2			; sourceSector = sourceCluster - 2
	lda sourceCluster+3
	sbc #$00
	sta sourceSector+3

	lda sectorsPerCluster
	sta source256

	clc
	lsr source256
	lda source256
	cmp #$00
	beq ClusterToLBAAddClusterBeginLBA	; handle 1 sector per cluster

ClusterToLBALoop:
	clc
	asl sourceSector
	rol sourceSector+1
	rol sourceSector+2			; sourceSector = sourceSector * sectorsPerCluster
	rol sourceSector+3
	clc
	lsr source256
	lda source256
	cmp #$00
	bne ClusterToLBALoop

ClusterToLBAAddClusterBeginLBA:
	clc
	lda sourceSector
	adc clusterBeginLBA
	sta sourceSector
	lda sourceSector+1
	adc clusterBeginLBA+1			; sourceSector = sourceSector(4) + clusterBeginLBA(4)
	sta sourceSector+1
	lda sourceSector+2
	adc clusterBeginLBA+2
	sta sourceSector+2
	lda sourceSector+3
	adc clusterBeginLBA+3
	sta sourceSector+3

ClusterToLBADone:

rts



CardLoadDirClearEntryName:
	lda #$00
	sta lfnFound

	ldy #$0000
;	lda #$00

-	sta tempEntry, y
	iny
	cpy #$0080
	bne -
rts



; ********************* Load dir from CF to buffer *********************

; Loads the contents of a directory and stores relevant files in the
; selected buffer (WRAM/SDRAM). bufferType is reset on RTS, so WRAM is
; the standard buffer.

; OLD COMMENTS:
;dest = sector dest  0200
;sourceEntry = where to get entry in 0200-0400, when overflow, load next sector
;destBank =  which bank to select in prg ram
;destEntry = where to put entry in prg ram 6000-7FFF, when overflow, increment bank

CardLoadDir:
	lda #>sectorBuffer1
	sta destHi				; sourceSector1 = where to put sector, where to read entry
	sta sourceEntryHi
	lda #<sectorBuffer1
	sta destLo
	sta sourceEntryLo
	stz destBank
	stz sourceEntryBank

	lda #$7F				; start at WRAM offset $7F0000
	sta destEntryBank
	stz destEntryHi
	stz destEntryLo

	lda #$00				; start at SDRAM offset $000000
	sta DMAWRITELO
	sta DMAWRITEHI
	sta DMAWRITEBANK

	stz filesInDir
	stz filesInDir+1
	stz sectorCounter
	stz temp
	stz temp+1
	stz selectedEntry
	stz selectedEntry+1
	stz lfnFound

	jump jClusterToLBA			; sourceCluster -> first sourceSector

	lda fat32Enabled
	cmp #$01
	beq CardLoadDirReadSector		; FAT32 go to read sector

	lda sourceCluster			; FAT16 check if trying to load root dir
	cmp rootDirCluster
	bne CardLoadDirReadSector
	lda sourceCluster+1
	cmp rootDirCluster+1
	bne CardLoadDirReadSector
	lda sourceCluster+2
	cmp rootDirCluster+2
	bne CardLoadDirReadSector
	lda sourceCluster+3
	cmp rootDirCluster+3
	bne CardLoadDirReadSector

	sec
	lda clusterBeginLBA
; FAT16 sourceSector = root dir first sector =>  clusterLBABegin(4) - fat16RootSectors(1)
	sbc fat16RootSectors
	sta sourceSector
	lda clusterBeginLBA+1
	sbc #$00
	sta sourceSector+1
	lda clusterBeginLBA+2
	sbc #$00
	sta sourceSector+2
	lda clusterBeginLBA+3
	sbc #$00
	sta sourceSector+3

CardLoadDirReadSector:
	lda #kDestWRAM
	sta destType

	jump jCardReadSector			; put into dest

	jump jCardLoadDirClearEntryName		; clear entry name



CardLoadDirLoop:
	ldy #$0000
	lda [sourceEntryLo], y			; if name[0] = 0x00, no more entries
	cmp #$00
	beq CardLoadDirLastEntryFound
	bra CardLoadDirCheckUnused

CardLoadDirLastEntryFound:

	stz bufferType				; reset bufferType variable
rts



CardLoadDirCheckUnused:
	ldy #$0000
	lda [sourceEntryLo], y
	cmp #$E5				; if name[0] = 0xE5, entry unused, skip
	bne CardLoadDirCheckLongName

	lda #$00
	sta lfnFound

	jmp CardLoadDirNextEntry



CardLoadDirCheckLongName:
	ldy #$000B
	lda [sourceEntryLo], y			; if flag = %00001111, long file name entry found
	and #$0F
	cmp #$0F
	bne ++

	ldy #$0000				; check first byte of LFN entry = ordinal field
	lda [sourceEntryLo], y
	and #%10111111				; mask off "last entry" bit

	cmp #$01				; if index = 1...8, load name
	bne +
	ldx #$0000				; index 1 = chars 0-12
	bra CardLoadDirLongName
+
	cmp #$02
	bne +
	ldx #$000D				; index 2 = chars 13-25
	bra CardLoadDirLongName
+
	cmp #$03
	bne +
	ldx #$001A				; index 3 = chars 26-38
	bra CardLoadDirLongName
+
	cmp #$04
	bne +
	ldx #$0027				; index 4 = chars 39-51
	bra CardLoadDirLongName
+
	cmp #$05
	bne +
	ldx #$0034				; index 5 = chars 52-64
	bra CardLoadDirLongName
+
	cmp #$06
	bne +
	ldx #$0041				; index 6 = chars 65-77
	bra CardLoadDirLongName
+
	cmp #$07
	bne +
	ldx #$004E				; index 7 = chars 78-90
	bra CardLoadDirLongName
+
	cmp #$08
	bne +
	ldx #$005B				; index 8 = chars 91-103
	bra CardLoadDirLongName
+
	jump jCardLoadDirClearEntryName		; else skip entry

	jmp CardLoadDirNextEntry

++
	bra CardLoadDirCheckShortName



CardLoadDirLongName:
	lda #$00
	sta tempEntry.tempCounter

	ldy #$0001

CardLoadDirLongNameLoop1:
	lda [sourceEntryLo], y			; loop thro 5 chars   1x3x5x7x9x
	cmp #$FF
	beq CardLoadDirLongNameLoop1FF
	sta tempEntry, x

CardLoadDirLongNameLoop1FF:
	inx
	iny
	iny
	inc tempEntry.tempCounter
	lda tempEntry.tempCounter
	cmp #$05
	bne CardLoadDirLongNameLoop1

	ldy #$000E

CardLoadDirLongNameLoop2:
	lda [sourceEntryLo], y			; loop thro 6 chars   Ex10x12x14x16x18x
	cmp #$FF
	beq CardLoadDirLongNameLoop2FF
	sta tempEntry, x

CardLoadDirLongNameLoop2FF:
	inx
	iny
	iny
	inc tempEntry.tempCounter
	lda tempEntry.tempCounter
	cmp #$0B
	bne CardLoadDirLongNameLoop2

	ldy #$001C

CardLoadDirLongNameLoop3:
	lda [sourceEntryLo], y			; thro 2 chars   1Cx1Ex
	cmp #$FF
	beq CardLoadDirLongNameLoop3FF
	sta tempEntry, x

CardLoadDirLongNameLoop3FF:
	inx
	iny
	iny
	lda [sourceEntryLo], y
	cmp #$FF
	beq CardLoadDirLongNameLoop4FF
	sta tempEntry, x

CardLoadDirLongNameLoop4FF:
	lda #$01
	sta lfnFound

	jmp CardLoadDirNextEntry



CardLoadDirCheckShortName:
	ldy #$000B
	lda [sourceEntryLo], y			; if flag = volume id, skip
	and #$08
	cmp #$08
	bne CardLoadDirCheckHidden

	jump jCardLoadDirClearEntryName

	lda #$00
	sta lfnFound

	jmp CardLoadDirNextEntry



CardLoadDirCheckHidden:
	ldy #$000B
	lda [sourceEntryLo], y
	and #$02
	cmp #$02				; if flag = 0x02, hidden, skip
	bne CardLoadDirCheckDir

	lda #$00
	sta lfnFound

	jump jCardLoadDirClearEntryName		; clear entry name

	jmp CardLoadDirNextEntry



CardLoadDirCheckDir:
	ldy #$000B
	lda [sourceEntryLo], y			; if flag = directory, load entry
	and #$10
	cmp #$10
	bne CardLoadDirCheckExt

	lda #$01
	sta tempEntry.tempDirFlag

	bra CardLoadDirShortName



CardLoadDirCheckExt:				; check entry extension
	ldx extNum
	dex					; backwards from the Nth (= $NNNN-1) to the 1st (= $0000) desired ext.

__CheckExtLoop:
	ldy #$0008

	lda [sourceEntryLo], y
	cmp extMatch1, x
	bne +

	iny
	lda [sourceEntryLo], y
	cmp extMatch2, x
	bne +

	iny
	lda [sourceEntryLo], y
	cmp extMatch3, x
	bne +

	bra CardLoadDirShortName		; extension matches, branch

+	dex					; otherwise, try next extension indicated
	bpl __CheckExtLoop

__NoExtMatch:
	lda #$00				; extension doesn't match, skip entry
	sta lfnFound

	jump jCardLoadDirClearEntryName

	jmp CardLoadDirNextEntry



CardLoadDirShortName:
	rep #A_8BIT				; A = 16 bit

	inc filesInDir				; increment file counter

	sep #A_8BIT				; A = 8 bit

	lda lfnFound
	cmp #$01
	beq CardLoadDirLongShortNameFound

CardLoadDirShortNameFound:
	ldy #$0000

CardLoadDirShortNameLoop:			; if lfnFound = 0, copy short name
	lda [sourceEntryLo], y
	sta tempEntry, y
	iny
	cpy #$0008
	bne CardLoadDirShortNameLoop

CardLoadDirShortFileName:
	lda tempEntry.tempDirFlag
	cmp #$01
	beq CardLoadDirSaveEntry

	lda #'.'
	sta tempEntry+$8
	ldy #$0008
	lda [sourceEntryLo], y			; copy short file name
	sta tempEntry+$9
	iny
	lda [sourceEntryLo], y
	sta tempEntry+$A
	iny
	lda [sourceEntryLo], y
	sta tempEntry+$B

	bra CardLoadDirSaveEntry



CardLoadDirLongShortNameFound:

CardLoadDirSaveEntry:
	ldy #$001A

	lda [sourceEntryLo], y			; copy clusterhilo to last 4 bytes of entry
	sta tempEntry.tempCluster

	iny

	lda [sourceEntryLo], y
	sta tempEntry.tempCluster+1

	ldy #$0014

	lda [sourceEntryLo], y
	sta tempEntry.tempCluster+2

	iny

	lda [sourceEntryLo], y
	sta tempEntry.tempCluster+3

	ldy #$0000

	lda bufferType				; check for buffer location (unspecified = $00 = WRAM)
	beq __SaveEntryToWRAMLoop



__SaveEntryToSDRAMLoop:				; copy entry to SDRAM
	lda tempEntry, y
	sta DMAREADDATA				; reminder: the DMA port auto-increments
	iny
	cpy #$0080
	bne __SaveEntryToSDRAMLoop

	rep #A_8BIT				; A = 16 bit, this saves a few lines of code during the next task :-)

	inc destEntryLo				; using destEntryLo (16 bit) as a temp counter here ;-)

	lda destEntryLo
	cmp #$FFFD				; check if counter has reached $FFFD (65533, max. no. of entries)
	bne +

	sep #A_8BIT				; if so, A = 8 bit

	jmp CardLoadDirLastEntryFound		; ... and don't process any more entries

+
	sep #A_8BIT				; otherwise, A = 8 bit

	jump jCardLoadDirClearEntryName		; ... and continue

	bra CardLoadDirNextEntry



__SaveEntryToWRAMLoop:				; copy entry to WRAM
	lda tempEntry, y
	sta [destEntryLo], y
	iny
	cpy #$0080
	bne __SaveEntryToWRAMLoop

	rep #A_8BIT				; A = 16 bit, this saves a few lines of code during the next task :-)

	clc
	lda destEntryLo				; destEntryHiLo += 128
	adc #$80
	sta destEntryLo

	cmp #$FF80				; check if destEntryHiLo = $FF80
	bne +

	sep #A_8BIT				; if so, A = 8 bit

	jmp CardLoadDirLastEntryFound		; ... and don't process any more entries

+
	sep #A_8BIT				; otherwise, A = 8 bit

	jump jCardLoadDirClearEntryName		; ... and continue



CardLoadDirNextEntry:
	clc					; increment entry source address
	lda sourceEntryLo			; sourceEntry += 32 in 0200-0400
	adc #$20
	sta sourceEntryLo
	lda sourceEntryHi
	adc #$00
	sta sourceEntryHi

	lda sourceEntryHi			; if source overflows, get next sector
	cmp #>sectorBuffer1+$02			; LAST CHANGE
	beq CardLoadDirNextSector

	jmp CardLoadDirLoop



CardLoadDirNextSector:
	clc
	lda sourceSector
	adc #$01
	sta sourceSector			; go to next sector num
	lda sourceSector+1
	adc #$00
	sta sourceSector+1
	lda sourceSector+2
	adc #$00
	sta sourceSector+2
	lda sourceSector+3
	adc #$00
	sta sourceSector+3

	lda fat32Enabled			; if FAT32, go to CardLoadDirSectorInc
	cmp #$01
	beq CardLoadDirSectorInc

	lda sourceCluster			; FAT16 check if trying to load root dir
	cmp rootDirCluster
	bne CardLoadDirSectorInc
	lda sourceCluster+1
	cmp rootDirCluster+1
	bne CardLoadDirSectorInc
	lda sourceCluster+2
	cmp rootDirCluster+2
	bne CardLoadDirSectorInc
	lda sourceCluster+3
	cmp rootDirCluster+3
	bne CardLoadDirSectorInc

	clc
	lda sectorCounter			; FAT16 root dir all sequential sectors
	adc #$01
	sta sectorCounter

	clc
	lda sectorCounter
	cmp fat16RootSectors			; if sectorCounter = fat16RootSectors,
	beq CardLoadDirLastEntryFoundJmp	; go to CardLoadDirLastEntryFound
	bra CardLoadDirLoadNextSector		; FAT16 skip cluster lookup when max root sectors not reached

CardLoadDirLastEntryFoundJmp:
	jmp CardLoadDirLastEntryFound		; FAT16 max root sectors reached, all root entries found



CardLoadDirSectorInc:
	clc
	lda sectorCounter			; one more sector
	adc #$01
	sta sectorCounter
	cmp sectorsPerCluster			; make sure cluster isn't overflowing
	bne CardLoadDirLoadNextSector

	jump jNextCluster			; move to next cluster



CardLoadDirLastEntryCheck:
	lda #$0F
	sta temp
	lda #$FF
	sta temp+1				; FAT32 last cluster = 0x0FFFFFFF
	sta temp+2
	sta temp+3

	lda fat32Enabled
	cmp #$01
	beq CardLoadDirLastEntryCheck2		; if FAT32, last cluster mask done

	lda #$00				; FAT16 last cluster = 0x0000FFFF
	sta temp
	sta temp+1

CardLoadDirLastEntryCheck2:			; if cluster = last cluster, jump to last entry found
	lda temp
	cmp sourceCluster+3
	bne CardLoadDirNextSectorNum
	lda temp+1
	cmp sourceCluster+2
	bne CardLoadDirNextSectorNum
	lda temp+2
	cmp sourceCluster+1
	bne CardLoadDirNextSectorNum
	lda temp+3
	cmp sourceCluster+0
	bne CardLoadDirNextSectorNum

	jmp CardLoadDirLastEntryFound



CardLoadDirNextSectorNum:
	jump jClusterToLBA			; sourceCluster -> first sourceSector

	lda #$00
	sta sectorCounter			; reset sector counter

CardLoadDirLoadNextSector:
	lda #<sectorBuffer1
	sta destLo				; reset sector dest
	sta sourceEntryLo			; reset entry source
	lda #>sectorBuffer1
	sta destHi
	sta sourceEntryHi
	stz destBank
	stz sourceEntryBank
	lda #kDestWRAM
	sta destType

	jump jCardReadSector

	jmp CardLoadDirLoop

; **********************************************************************



NextCluster:    ;load fat entry for sourceCluster, store next cluster number into sourceCluster
  ;fat16:
    ; offset = clusternum << 1
    ;mask = 00 00 ff ff
	asl sourceCluster
	rol sourceCluster+1
	rol sourceCluster+2
	rol sourceCluster+3
  ;fat32:
    ;offset = clutsernum << 2       cluster 2 << 2 = 8
    ;mask = 0f ff ff ff
	lda fat32Enabled
	cmp #$00
	beq NextClusterSectorNum

	asl sourceCluster
	rol sourceCluster+1
	rol sourceCluster+2
	rol sourceCluster+3

NextClusterSectorNum:
  ;fat sector num = fatBeginLBA + (offset / 512)     cluster = $2f8
	lda sourceCluster+1
	sta sourceSector+0
	lda sourceCluster+2
	sta sourceSector+1
	lda sourceCluster+3			; divide by 256   sector = 02
	sta sourceSector+2
	lda #$00
	sta sourceSector+3

	lsr sourceSector+3			; divide by 512   sector = 01
	ror sourceSector+2
	ror sourceSector+1
	ror sourceSector+0
	clc
	lda sourceSector
	adc fatBeginLBA
	sta sourceSector
	lda sourceSector+1			; add fatBeginLBA   sector = 60 = $c000
	adc fatBeginLBA+1
	sta sourceSector+1
	lda sourceSector+2
	adc fatBeginLBA+2
	sta sourceSector+2
	lda sourceSector+3
	adc fatBeginLBA+3
	sta sourceSector+3

	lda #>sectorBuffer1			; load FAT sector
	sta destHi
	lda #<sectorBuffer1
	sta destLo
	stz destBank
	lda #kDestWRAM
	sta destType
	jump jCardReadSector

  ;offset = offset % 512    ;offset of fat entry within loaded sector 0-511
	lda sourceCluster+1
	and #%00000001
	sta sourceCluster+1			; cluster+1=0

	lda #<sectorBuffer1			; next cluster = [sector], offset
	sta sourceLo
	stz sourceBank

; sourceHi = sectorBuffer1(high) or sectorBuffer1(high)+1 for which 256 byte block too look in
	lda #>sectorBuffer1
	adc sourceCluster+1
	sta sourceHi

	lda sourceCluster
	sta temp+2
	stz temp+3
	ldy temp+2
	ldx #$0000

NextClusterLoop:
	lda [sourceLo], y
	sta sourceCluster, x
	iny
	inx
	cpx #$0004
	bne NextClusterLoop

	lda sourceCluster+3			; FAT32 mask off top 4 bits
	and #$0F
	sta sourceCluster+3

	lda fat32Enabled
	cmp #$01
	beq NextClusterDone			; no more mask for FAT32

	lda #$00
	sta sourceCluster+3			; FAT16 mask
	sta sourceCluster+2

NextClusterDone:

rts



; ********************** Print directory content ***********************

DirPrintDir:					; loop through entries 0 to #maxFiles or 0 to filesInDir
	jump jPrintClearScreen

	stz selectedEntry
	stz selectedEntry+1

	SetCursorPos 0, 0

__DirPrintDirLoop:
	jump jDirPrintEntry

	rep #A_8BIT				; A = 16 bit

	inc selectedEntry			; increment entry index

	lda selectedEntry
	cmp #maxFiles				; check if printY max reached, jump out
	beq __DirPrintDirLoopDone

	cmp filesInDir				; check if last file reached, jump out
	beq __DirPrintDirLoopDone

	sep #A_8BIT				; A = 8 bit

	bra __DirPrintDirLoop

__DirPrintDirLoopDone:
	stz selectedEntry			; reset entry index

	sep #A_8BIT				; A = 8 bit

	lda #$0D				; in 1-byte/1-pixel-steps
	sta cursorX				; indent cursor, too

	lda #cursorYmin
	sta cursorY

	stz cursorYCounter
	stz cursorYUp
	stz cursorYDown

	stz scrollY
	stz scrollYCounter
	stz scrollYUp
	stz scrollYDown

	stz speedCounter
	stz speedScroll

	lda #insertStandardTop
	sta insertTop

	lda #insertStandardBottom
	sta insertBottom
rts



; ************************* Print single entry *************************

DirPrintEntry:
	lda #'S'
	sta bufferType				; only ever print SDRAM buffer entries (??)

	jump jDirGetEntry

	stz tempEntry+56			; NUL-terminate entry string after 56 characters

	lda #<tempEntry
	sta strPtr
	lda #>tempEntry
	sta strPtr+1
	ldy #strPtr

	lda tempEntry.tempDirFlag		; if dir flag = $01, we print a slash before the entry name
	beq __PrintFileOnly

	PrintString " /%s\n"
	bra __DirPrintEntryDone

__PrintFileOnly:
	PrintString "  %s\n"

__DirPrintEntryDone:

	stz bufferType				; reset bufferType variable
rts



; ********************** Get entry into tempEntry **********************

; This function calculates selectedEntry's buffer address, then copies
; the 128-byte-long entry to the tempEntry variable.
;
; WRAM procedure (using the upper 64K only):
; sourceEntryLo[16bit] = selectedEntry[16bit] * 128
; max. $1FF(+1) entries, last entry's address = $FF80
;
; SDRAM procedure (using the lower 8MB only):
; DMAWRITELO[24bit] = selectedEntry[16bit] * 128
; max. $FFFD(+1) entries, last entry's address = $7FFE80
;
; Calculation code using bitwise operations is based on a code snippet
; by thefox. We "shift" selectedEntry[16bit] left 8 bits (no actual
; shifting because it's on byte boundary), then shift the whole value
; right one bit. Works great! :D

DirGetEntry:
	lda bufferType				; check for buffer location (unspecified = $00 = WRAM)
	beq __GetEntryFromWRAM

	lda selectedEntry+1			; get entry from SDRAM
	lsr a
	sta DMAWRITEBANK

	lda selectedEntry
	ror a
	sta DMAWRITEHI

	lda #$00
	ror a
	sta DMAWRITELO

	ldy #$0000

__GetEntryFromSDRAMLoop:
	lda DMAREADDATA
	sta tempEntry, y
	iny
	cpy #$0080
	bne __GetEntryFromSDRAMLoop
rts



__GetEntryFromWRAM:
	lda #$7F
	sta sourceEntryBank

	lda selectedEntry+1
	lsr a					; selectedEntry+1 into carry bit

	lda selectedEntry
	ror a
	sta sourceEntryHi

	lda #$00
	ror a
	sta sourceEntryLo

	ldy #$0000

__GetEntryFromWRAMLoop:
	lda [sourceEntryLo], y
	sta tempEntry, y
	iny
	cpy #$0080
	bne __GetEntryFromWRAMLoop
rts



; ************************ Find specific entry *************************

; New:
; - Uses a 16 bit accumulator where possible for speed (v2.01)
; - Error message gives full filename (with extension) in case the file
;   isn't found (v2.00)

DirFindEntry:
	rep #A_8BIT				; A = 16 bit

	stz selectedEntry			; reset selectedEntry

	lda filesInDir				; only do the search if directory isn't empty
	beq __DirFindEntryFailed

__DirFindEntryLoop:
	sep #A_8BIT				; A = 8 bit

	jump jDirGetEntry

	ldy #$0000

__DirFindEntryCharLoop:				; check if entry matches, only look at first 8 chars
	lda tempEntry, y
	cmp findEntry, y
	bne __DirFindEntryNext
	iny
	cpy #$0008
	bne __DirFindEntryCharLoop
rts						; all 8 chars match

__DirFindEntryNext:
	rep #A_8BIT				; A = 16 bit

	inc selectedEntry			; increment to next entry index

	lda selectedEntry			; check for max. no. of files
	cmp filesInDir
	bne __DirFindEntryLoop

__DirFindEntryFailed:
	sep #A_8BIT				; A = 8 bit

	ClearLine 20
	ClearLine 21				; hide button assignment hints
	ClearLine 22

	SetCursorPos 20, 6

	ldx #$0000

-	lda findEntry, x
	cmp #' '				; only load actual filename characters to print 
	beq +
	inx
	cpx #$0008
	bne -

+	stz findEntry, x			; NUL-terminate filename string at first space, or after 8 chars

	lda #<findEntry
	sta strPtr
	lda #>findEntry
	sta strPtr+1

	ldy #strPtr

	PrintString "Error: %s"

	lda tempEntry.tempDirFlag		; if directory, skip printing of file extension
	cmp #$01
	beq +

	lda extMatch1				; load file extension into tempEntry for printing
	sta tempEntry
	lda extMatch2
	sta tempEntry+1
	lda extMatch3
	sta tempEntry+2
	stz tempEntry+3				; NUL-terminate file extension string

	lda #<tempEntry
	sta strPtr
	lda #>tempEntry
	sta strPtr+1

	ldy #strPtr

	PrintString ".%s"			; result: e.g. "Error: SI.MAP file not found!"
+	PrintString " file not found!"		; or (if dir) "Error: POWERPAK file not found!"

	jump jForever



; ************************** Load CF modules ***************************

CardLoadModule:					; expects module file sourceCluster set via FindFile macro!
	lda #<codeBuffer
	sta destLo
	lda #>codeBuffer
	sta destHi				; put into code RAM
	lda #$00
	sta destBank

	stz sectorCounter
	stz bankCounter

	jump jClusterToLBA			; sourceCluster -> first sourceSector

;  SetCursorPos 1, 1
;  PrintString "CardLoadModuleLoop\n"

CardLoadModuleLoop:
;  SetCursorPos 14, 1
;  PrintHexNum bankCounter
;  PrintString "="
;  PrintHexNum destBank
;  PrintHexNum destHi
;  PrintHexNum destLo
;  PrintString "  "
;  PrintHexNum sourceCluster+3
;  PrintHexNum sourceCluster+2
;  PrintHexNum sourceCluster+1
;  PrintHexNum sourceCluster+0
;  PrintString "  "
;  PrintHexNum sourceSector+3
;  PrintHexNum sourceSector+2
;  PrintHexNum sourceSector+1
;  PrintHexNum sourceSector+0
;  PrintString "\n"

	lda #kDestWRAM
	sta destType

	jump jCardReadSector			; sector -> code RAM

 ; PrintHexNum bankCounter
 ; PrintString "read done\n"

	lda destHi
	pha
	lda destLo
	pha

	jump jLoadNextSectorNum

	pla
	sta destLo
	pla
	sta destHi

CardLoadModuleLastSectorCheck:
	lda #$0F
	sta temp
	lda #$FF
	sta temp+1				; FAT32 last cluster = 0x0FFFFFFF
	sta temp+2
	sta temp+3

	lda fat32Enabled
	cmp #$01
	beq CardLoadModuleLastSectorCheck2	; if FAT32, last cluster mask done

	lda #$00
	sta temp
	sta temp+1				; FAT16 last cluster = 0x0000FFFF

CardLoadModuleLastSectorCheck2:			; if cluster = last cluster, jump to last entry found
	lda temp
	cmp sourceCluster+3
	bne CardLoadModuleNextSector
	lda temp+1
	cmp sourceCluster+2
	bne CardLoadModuleNextSector
	lda temp+2
	cmp sourceCluster+1
	bne CardLoadModuleNextSector
	lda temp+3
	cmp sourceCluster+0
	bne CardLoadModuleNextSector
	bra CardLoadModuleDone

CardLoadModuleNextSector:
	inc destHi
	inc destHi
	inc bankCounter
	lda bankCounter
	cmp #$0A				; only load 10x512=5KB for modules
	beq CardLoadModuleDone
	bra CardLoadModuleLoop

CardLoadModuleDone:
;  PrintString "CardLoadModuleDone\n"
;  PrintHexNum destBank
;  PrintHexNum destHi
;  PrintHexNum destLo
;  PrintString "  "
;  PrintHexNum sourceCluster+3
;  PrintHexNum sourceCluster+2
;  PrintHexNum sourceCluster+1
;  PrintHexNum sourceCluster+0
;  PrintString "\n"
	stz scrollY
	stz scrollYCounter
	stz scrollYUp
	stz scrollYDown
; jmp Forever

	tsx					; Clean up the stack, this is necessary to avoid a stack overflow
	cpx #$1FFB				; that already plagued v1.0X and usually occurred after many module
	bcs +					; loads. It was likely caused by the PHX/JSR in the jump macro, from
	pla					; where there is no RTS (and thus, no PLX) once a new module is loaded.
	pla					; Test results showed that S = S - 4 bytes per "jump jCardLoadModule",
	pla					; so 4x PLA should suffice as a remedy. :-) (We don't want a stack
	pla					; underflow either, hence the CPX/BCS combo.)
+
	jml codeBuffer				; go to module begin



; get next sector, use sectorCounter to check if next cluster needed
LoadNextSectorNum:
	clc
	lda sourceSector
	adc #$01
	sta sourceSector			; go to next sector num
	lda sourceSector+1
	adc #$00
	sta sourceSector+1
	lda sourceSector+2
	adc #$00
	sta sourceSector+2
	lda sourceSector+3
	adc #$00
	sta sourceSector+3

	clc
	lda sectorCounter			; one more sector
	adc #$01
	sta sectorCounter
	cmp sectorsPerCluster
	beq LoadNextClusterNum
rts

LoadNextClusterNum:
	lda #$00
	sta sectorCounter

	jump jNextCluster			; get cluster num into sourceCluster from FAT table

	jump jClusterToLBA			; get sector num into sourceSector
rts



; *********************** Load another directory ***********************

NextDir:
	lda tempEntry.tempCluster
	sta sourceCluster
	lda tempEntry.tempCluster+1
	sta sourceCluster+1
	lda tempEntry.tempCluster+2
	sta sourceCluster+2
	lda tempEntry.tempCluster+3
	sta sourceCluster+3			; load dir selected

	lda sourceCluster			; check if cluster = root dir
	cmp #$00
	bne __NotRootDir

	lda sourceCluster+1
	cmp #$00
	bne __NotRootDir

	lda sourceCluster+2
	cmp #$00
	bne __NotRootDir

	lda sourceCluster+3
	cmp #$00
	bne __NotRootDir

	lda rootDirCluster
	sta sourceCluster
	lda rootDirCluster+1
	sta sourceCluster+1
	lda rootDirCluster+2
	sta sourceCluster+2
	lda rootDirCluster+3
	sta sourceCluster+3

__NotRootDir:
	jsr ShowLoadingMsg

	jump jCardLoadDir

	jump jDirPrintDir			; this includes PrintClearScreen / SetCursorPos 0, 0
rts



; ***************************** Load FPGA ******************************

CardLoadFPGA:
;  PrintString "Loading FPGA\n"

	lda #$01
	sta FPGAPROGRAMWRITE			; SEND PROGRAM SIGNAL TO FPGA
	lda #$00
	sta FPGAPROGRAMWRITE			; SEND PROGRAM SIGNAL TO FPGA
	wai
	wai
	lda #$01
	sta FPGAPROGRAMWRITE			; SEND PROGRAM SIGNAL TO FPGA

	stz sectorCounter			; BIT file cluster already in sourceCluster
	stz bankCounter

	jump jClusterToLBA			; sourceCluster -> first sourceSector

;  SetCursorPos 1, 1
;  PrintString "CardLoadModuleLoop\n"

	wai
	lda #$80
	sta $2100				; turn screen off

CardLoadFPGALoop:
;  SetCursorPos 14, 1
;  PrintHexNum bankCounter
;  PrintString "="
;  PrintHexNum destBank
;  PrintHexNum destHi
;  PrintHexNum destLo
;  PrintString "  "
;  PrintHexNum sourceCluster+3
;  PrintHexNum sourceCluster+2
;  PrintHexNum sourceCluster+1
;  PrintHexNum sourceCluster+0
;  PrintString "  "
;  PrintHexNum sourceSector+3
;  PrintHexNum sourceSector+2
;  PrintHexNum sourceSector+1
;  PrintHexNum sourceSector+0
;  PrintString "\n"

	lda #kDestFPGA
	sta destType

	jump jCardReadSector			; sector -> FPGA

 ; PrintHexNum bankCounter
 ; PrintString "read done\n"

	jump jLoadNextSectorNum



CardLoadFPGALastSectorCheck:
	lda #$0F
	sta temp
	lda #$FF
	sta temp+1				; FAT32 last cluster = 0x0FFFFFFF
	sta temp+2
	sta temp+3

	lda fat32Enabled
	cmp #$01
	beq CardLoadFPGALastSectorCheck2	; if FAT32, last cluster mask done

	lda #$00
	sta temp
	sta temp+1				; FAT16 last cluster = 0x0000FFFF

CardLoadFPGALastSectorCheck2:			; if cluster = last cluster, jump to last entry found
	lda temp
	cmp sourceCluster+3
	bne CardLoadFPGANextSector
	lda temp+1
	cmp sourceCluster+2
	bne CardLoadFPGANextSector
	lda temp+2
	cmp sourceCluster+1
	bne CardLoadFPGANextSector
	lda temp+3
	cmp sourceCluster+0
	bne CardLoadFPGANextSector
	bra CardLoadFPGADone

CardLoadFPGANextSector:
	inc bankCounter
	lda bankCounter
	cmp #$6B				; 437312 bits = 54664 bytes = 107 sectors = $6B
	beq CardLoadFPGADone
	bra CardLoadFPGALoop

CardLoadFPGADone:
;  PrintString "Loading FPGA DONE\n"
	lda #$0F
	sta $2100				; turn screen on
rts



; ************************* GameGenie Handler **************************

GameGenieClear:					; clears out one GG code at a time, expects code no. set to Y
	ldx #$0000				; (#$0000 = code 1, #$0008 = code 2, ... #$0020 = code 5)
	lda #$10				; $10 = underscore on code display

-	sta gameGenie, y
	iny
	inx
	cpx #$0008
	bne -
rts



GameGenieCharDB:
	.db '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '_'

GGCharConvertedToHexDB:
	.db $04, $06, $0D, $0E, $02, $07, $08, $03, $0B, $05, $0C, $09, $0A, $00, $0F, $01, $00



GameGeniePrint:
	phy
	jsr CardLoadDirClearEntryName
	lda #$00
	sta gameGenieOffset+1
	ply

	lda gameGenie, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry
	lda #' '
	sta tempEntry+1
	sta tempEntry+2
	sta tempEntry+3

	lda gameGenie+1, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry+4
	lda #' '
	sta tempEntry+5
	sta tempEntry+6
	sta tempEntry+7

	lda gameGenie+2, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry+8
	lda #' '
	sta tempEntry+9
	sta tempEntry+10
	sta tempEntry+11

	lda gameGenie+3, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry+12
	lda #' '
	sta tempEntry+13
	sta tempEntry+14
	sta tempEntry+15

	lda gameGenie+4, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry+16
	lda #' '
	sta tempEntry+17
	sta tempEntry+18
	sta tempEntry+19

	lda gameGenie+5, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry+20
	lda #' '
	sta tempEntry+21
	sta tempEntry+22
	sta tempEntry+23

	lda gameGenie+6, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry+24
	lda #' '
	sta tempEntry+25
	sta tempEntry+26
	sta tempEntry+27

	lda gameGenie+7, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GameGenieCharDB, x
	sta tempEntry+28
	lda #$00
	sta tempEntry+29

	lda #<tempEntry
	sta strPtr
	lda #>tempEntry
	sta strPtr+1
	ldy #strPtr
	PrintString "%s"
rts



GameGenieDecode:
	lda #$00
	sta gameGenieOffset+1

	lda gameGenie, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry

	lda gameGenie+1, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry+1

	lda gameGenie+2, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry+2

	lda gameGenie+3, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry+3

	lda gameGenie+4, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry+4

	lda gameGenie+5, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry+5

	lda gameGenie+6, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry+6

	lda gameGenie+7, y
	sta gameGenieOffset
	ldx gameGenieOffset
	lda.l GGCharConvertedToHexDB, x
	sta tempEntry+7

	lda tempEntry
	asl a
	asl a
	asl a
	asl a
	ora tempEntry+1
	sta gameGenieDecode, y			; DATA done

	lda tempEntry+4				;xxxxxxAB
	asl a
	asl a
	asl a
	asl a
	asl a
	asl a
	and #$C0
	sta temp				; ABxxxxxx
	lda tempEntry+5				; xxxxCDxx
	asl a
	asl a
	and #$30
	ora temp
	sta temp				; ABCDxxxx
	lda tempEntry+6				; xxxxxxEF
	asl a
	asl a
	and #$0C				; xxxxEFxx
	ora temp
	sta temp				; ABCDEFxx
	lda tempEntry+7				; xxxxGHxx
	lsr a
	lsr a
	and #$03				; xxxxxxGH
	ora temp
	sta temp				; ABCDEFGH
	sta gameGenieDecode+1, y

	lda tempEntry+2				; xxxxIJKL
	asl a
	asl a
	asl a
	asl a
	and #$F0
	sta temp				; IJKLxxxx
	lda tempEntry+7				; xxxxxxMN
	asl a
	asl a
	and #$0C				; xxxxMNxx
	ora temp
	sta temp				; IJKLMNxx
	lda tempEntry+4				; xxxxOPxx
	lsr a
	lsr a
	and #$03				; xxxxxxOP
	ora temp
	sta temp				; IJKLMNOP
	sta gameGenieDecode+2, y

	lda tempEntry+3				; xxxxQRST
	asl a
	asl a
	asl a
	asl a
	and #$F0
	sta temp				; QRSTxxxx
	lda tempEntry+5				; xxxxxxUV
	asl a
	asl a
	and #$0C
	ora temp				; xxxxUVxx
	sta temp				; QRSTUVxx
	lda tempEntry+6				; xxxxWXxx
	lsr a
	lsr a
	and #$03				; xxxxxxWX
	ora temp
	sta temp
	sta gameGenieDecode+3, y		; QRSTUVWX

	PrintString "$"
	lda gameGenieDecode+1, y
	sta temp
	PrintHexNum temp
	lda gameGenieDecode+2, y
	sta temp
	PrintHexNum temp
	lda gameGenieDecode+3, y
	sta temp
	PrintHexNum temp
	PrintString " = $"
	lda gameGenieDecode, y
	sta temp
	PrintHexNum temp
rts



GameGenieGetOffset:
	lda cursorY
	sec
	sbc #$60
	sta temp				; game genie 0,8,16,24,32
	lsr temp
	lda cursorX
	sec
	sbc #$40
	lsr a
	lsr a
	lsr a
	lsr a
	sta temp+1				; char 0..7
	lda temp
	clc
	adc temp+1
	sta gameGenieOffset
	lda #$00
	sta gameGenieOffset+1
rts



GameGenieNextChar:
	jsr GameGenieGetOffset
	ldx gameGenieOffset

	lda gameGenie, x
	clc
	adc #$01
	sta gameGenie, x

	lda gameGenie, x
	cmp #$11
	bne GameGenieCharStore

	lda #$00
	sta gameGenie, x

	bra GameGenieCharStore



GameGeniePrevChar:
	jsr GameGenieGetOffset
	ldx gameGenieOffset

	lda gameGenie, x
	sec
	sbc #$01
	sta gameGenie, x

	lda gameGenie, x
	cmp #$FF
	bne GameGenieCharStore
	lda #$10
	sta gameGenie, x
;	jmp GameGenieCharStore



GameGenieCharStore:				; prints codes being entered/edited by the user (!)
	lda cursorY
	cmp #$60
	beq GameGenieCharStore0
	cmp #$70
	beq GameGenieCharStore1
	cmp #$80
	beq GameGenieCharStore2
	cmp #$90
	beq GameGenieCharStore3
	cmp #$A0
	beq GameGenieCharStore4

GameGenieCharStore0:
	SetCursorPos 9, 7

	ldy #$0000

	jump jGameGeniePrint
rts

GameGenieCharStore1:
	SetCursorPos 11, 7

	ldy #$0008

	jump jGameGeniePrint
rts

GameGenieCharStore2:
	SetCursorPos 13, 7

	ldy #$0010

	jump jGameGeniePrint
rts

GameGenieCharStore3:
	SetCursorPos 15, 7

	ldy #$0018

	jump jGameGeniePrint
rts

GameGenieCharStore4:
	SetCursorPos 17, 7

	ldy #$0020

	jump jGameGeniePrint
rts



GameGenieWriteCode:
	PrintString "GG-> "

	jump jGameGenieDecode

 ; PrintString "\n"

	lda gameGenie, y
	cmp #16
	beq GameGenieWriteCodeSkip
	lda gameGenie+1, y
	cmp #16
	beq GameGenieWriteCodeSkip
	lda gameGenie+2, y
	cmp #16
	beq GameGenieWriteCodeSkip
	lda gameGenie+3, y
	cmp #16
	beq GameGenieWriteCodeSkip
	lda gameGenie+4, y
	cmp #16
	beq GameGenieWriteCodeSkip
	lda gameGenie+5, y
	cmp #16
	beq GameGenieWriteCodeSkip
	lda gameGenie+6, y
	cmp #16
	beq GameGenieWriteCodeSkip
	lda gameGenie+7, y
	cmp #16
	beq GameGenieWriteCodeSkip
	bra GameGenieWriteCodeGood

GameGenieWriteCodeSkip:
	PrintString " code unused"
	jmp GameGenieWriteCodeDone

GameGenieWriteCodeGood:
	lda gameGenieDecode, y			; data
	sta ggcode
	lda gameGenieDecode+1, y		; bank
	sta ggcode+1
	lda gameGenieDecode+2, y		; high
	sta ggcode+2
	lda gameGenieDecode+3, y		; low
	sta ggcode+3

	lda #$00
	sta CONFIGWRITESRAMSIZE

;PrintString "$F0"
;lda ggcode+2
;sta errorCode
;  PrintHexNum ggcode+1
;  PrintHexNum ggcode+2
;  PrintHexNum ggcode+3
;lda ggcode+3
;sta errorCode
;PrintHexNum errorCode

;PrintString "<=$"
;lda ggcode
;sta errorCode
;PrintHexNum errorCode

; jsr Delay5Sec

	lda ggcode+1				; GG addr = bbhhll
	and #$F0
	lsr a
	lsr a					; bank index = bb >> 3  Fx->1F
	lsr a
	sta sourceLo
	PrintString " b="
	PrintHexNum sourceLo
	lda #$00
	sta sourceHi
	ldx sourceLo
	lda gameBanks, x
	sta errorCode
	inx					; THIS IS WRONG?  SHOULD BE +$10?

	lda gameBanks, x
	sta errorCode+1

; jsr Delay5Sec

	lda errorCode

; and #$20
; asl a
; ora errorCode
;  ora #$40       ;;make writeable
;  sta errorCode

	sta CONFIGWRITEBANK+$1E0		; put indexed bank into F0low reg
	PrintString "blo="
	PrintHexNum errorCode

;  jsr Delay5Sec

	lda errorCode+1

;  and #$20
;  asl a
;  ora errorCode+1
;  sta errorCode+1

	sta CONFIGWRITEBANK+$1F0		; put indexed bank into F0hi reg

	PrintString "bhi="
	PrintHexNum errorCode+1

;  jsr Delay5Sec

	lda ggcode+3
	sta destLo
	lda ggcode+2
	sta destHi
	lda ggcode+1
	and #$0F
	sta errorCode
	PrintHexNum errorCode
	PrintHexNum destHi
	PrintHexNum destLo
	ldx destLo
	lda errorCode
	cmp #$00
	beq GGF0
	cmp #$01
	beq GGF1
	cmp #$02
	beq GGF2
	cmp #$03
	beq GGF3
	cmp #$04
	beq GGF4
	cmp #$05
	beq GGF5
	cmp #$06
	beq GGF6
	cmp #$07
	beq GGF7
	bra GGFjump

GGF0:
	lda ggcode				; write GG data to F0hhll
	sta $F00000, x
	jmp GGCheck

GGF1:
	lda ggcode				; write GG data to F0hhll
	sta $F10000, x
	jmp GGCheck

GGF2:
	lda ggcode				; write GG data to F0hhll
	sta $F20000, x
	jmp GGCheck

GGF3:
	lda ggcode				; write GG data to F0hhll
	sta $F30000, x
	bra GGCheck

GGF4:
	lda ggcode				; write GG data to F0hhll
	sta $F40000, x
	bra GGCheck

GGF5:
	lda ggcode				; write GG data to F0hhll
	sta $F50000, x
	bra GGCheck

GGF6:
	lda ggcode				; write GG data to F0hhll
	sta $F60000, x
	bra GGCheck

GGF7:
	lda ggcode				; write GG data to F0hhll
	sta $F70000, x
	bra GGCheck

GGFjump:
	cmp #$08
	beq GGF8
	cmp #$09
	beq GGF9
	cmp #$0A
	beq GGFA
	cmp #$0B
	beq GGFB
	cmp #$0C
	beq GGFC
	cmp #$0D
	beq GGFD
	cmp #$0E
	beq GGFE
	cmp #$0F
	beq GGFF

GGF8:
	lda ggcode				; write GG data to F0hhll
	sta $F80000, x
	bra GGCheck

GGF9:
	lda ggcode				; write GG data to F0hhll
	sta $F90000, x
	bra GGCheck

GGFA:
	lda ggcode				; write GG data to F0hhll
	sta $FA0000, x
	bra GGCheck

GGFB:
	lda ggcode				; write GG data to F0hhll
	sta $FB0000, x
	bra GGCheck

GGFC:
	lda ggcode				; write GG data to F0hhll
	sta $FC0000, x
	bra GGCheck

GGFD:
	lda ggcode				; write GG data to F0hhll
	sta $FD0000, x
	bra GGCheck

GGFE:
	lda ggcode				; write GG data to F0hhll
	sta $FE0000, x
	bra GGCheck

GGFF:
	lda ggcode				; write GG data to F0hhll
	sta $FF0000, x
;	bra GGCheck

GGCheck:
	lda $F00000, x
	sta errorCode
	stx sourceLo

;  PrintString "c="
;  PrintHexNum errorCode

;  PrintString " a="
;  PrintHexNum sourceLo+1
;  PrintHexNum sourceLo

;  jsr Delay5Sec
;  jsr Delay5Sec

	lda sramSizeByte
	sta CONFIGWRITESRAMSIZE
	lda gameBanks+$1E
	sta CONFIGWRITEBANK+$1E0		; put bank back
	lda gameBanks+$1F
	sta CONFIGWRITEBANK+$1F0		; put bank back

GameGenieWriteCodeDone:

rts



; ************************ 5-second-long delay *************************

Delay5Sec:
	ldx #$00AC				; 172 frames, actually

-	wai
	dex
	bne -
rts



; **************************** SDRAM check *****************************

MemCheck:
	wai
	ClearLine 16
	ClearLine 17
	ClearLine 18

	SetCursorPos 16, 1
	PrintString "SDRAM check ..."

	SetCursorPos 22, 11
	PrintString " B: cancel"

	stz errorCode
	stz temp
	stz temp+1
	stz temp+2

	lda #$00
	sta DMAWRITEBANK
	sta DMAWRITELO
	sta DMAWRITEHI

	SetCursorPos 17, 1
	PrintString "Writing bank:"

MemCheckWriteLoop:
	lda Joy1New+1				; check for user input
	and #%10000000				; B button
	beq +

	SetCursorPos 16, 7
	PrintString "cancelled!"

	jsr Delay5Sec

	ClearLine 16
	ClearLine 17
rts

+	lda errorCode
	sta DMAREADDATA
	inc errorCode

	lda temp+2
	sta temp+3
	lda temp
	clc
	adc #$0F
	sta temp
	lda temp+1
	adc #$00
	sta temp+1
	lda temp+2
	adc #$00
	sta temp+2
	cmp temp+3
	beq MemCheckWriteLoopNext
	jsr MemCheckUpdateBank

MemCheckWriteLoopNext:
	lda temp+2
	cmp #$FF
	bne MemCheckWriteLoop

	stz errorCode
	stz temp
	stz temp+1
	stz temp+2

	lda #$00
	sta DMAWRITEBANK
	sta DMAWRITELO
	sta DMAWRITEHI

	SetCursorPos 17, 1
	PrintString "Read"			; "Reading bank:"

MemCheckReadLoop:
	lda Joy1New+1				; check for user input
	and #%10000000				; B button
	beq +

	SetCursorPos 16, 7
	PrintString "cancelled!"

	jsr Delay5Sec

	ClearLine 16
	ClearLine 17
rts

+	lda DMAREADDATA
	sta temp+4
	cmp errorCode
	bne MemCheckError

	inc errorCode

	lda temp+2
	sta temp+3
	lda temp
	clc
	adc #$0F
	sta temp
	lda temp+1
	adc #$00
	sta temp+1
	lda temp+2
	adc #$00
	sta temp+2
	cmp temp+3
	beq MemCheckReadLoopNext
	jsr MemCheckUpdateBank

MemCheckReadLoopNext:
	lda temp+2
	cmp #$FF
	bne MemCheckReadLoop

	SetCursorPos 16, 7
	PrintString "passed!"

	ClearLine 17
rts



MemCheckError:
	ClearLine 22				; remove cancel button hint

	SetCursorPos 16, 4
	PrintString "ERROR!   "			; "SDRAM ERROR!"

	SetCursorPos 17, 9
	PrintString ", read byte value: "
	PrintHexNum temp+4

	SetCursorPos 18, 1
	PrintString "Expected byte value: "
	PrintHexNum errorCode

	PrintString " at offset $"
	PrintHexNum temp+2
	PrintHexNum temp+1
	PrintHexNum temp

	SetCursorPos 19, 1
	PrintString "Trying again 4 times:"

	ldy #$0004				; 4 retries, the exact amount doesn't really matter ;-)

-	dey
	PrintString "  "

	lda temp+2
	sta DMAWRITEBANK
	lda temp+1
	sta DMAWRITEHI
	lda temp+0
	sta DMAWRITELO

	lda DMAREADDATA
	sta temp+4
	PrintHexNum temp+4

	cpy #$0000
	bne -

	SetCursorPos 21, 1
	PrintString "CRITICAL HARDWARE ERROR! PLEASE CHECK LOG.TXT!"

	jump jLogScreen				; save to LOG.TXT for later review

	jump jForever				; SDRAM error means potentially faulty PowerPak --> halt



MemCheckUpdateBank:
	SetCursorPos 17, 8
	PrintHexNum temp+2			; shows bank no. while writing/reading SDRAM
rts



; ************************* Clear "find entry" *************************

ClearFindEntry:
	lda #' '
	sta findEntry
	sta findEntry+1
	sta findEntry+2
	sta findEntry+3
	sta findEntry+4
	sta findEntry+5
	sta findEntry+6
	sta findEntry+7
rts



; ************************ Load ROM information ************************

CopyROMInfo:
	lda DMAREADDATA				; D5
	sta errorCode
	and #%11101111				; mask off fast/slow
	sta gameROMMapper
	PrintString "\nMAP"
	PrintHexNum errorCode
	lda DMAREADDATA				; D6
	sta gameROMType
	PrintString " TYP"
	PrintHexNum gameROMType
	lda DMAREADDATA				; D7
;  sta gameROMSize  taken from file size
	sta errorCode
	PrintString " ROM"
	PrintHexNum errorCode
	lda DMAREADDATA				; D8
	sta saveSize
	PrintString " SRM"
	PrintHexNum saveSize

	ldy #$0024				; 36 bytes D9-FC

CopyROMInfoLoop:
	lda DMAREADDATA
	dey
	cpy #$0000
	bne CopyROMInfoLoop

	sta gameResetVector
	lda DMAREADDATA				; FD
	sta gameResetVector+1

	PrintString " RST"
	PrintHexNum gameResetVector+1
	PrintHexNum gameResetVector
rts



CopyBanks:
	ldy #$0000
	lda [destLo], y
	sta CONFIGWRITEBANK+$010
	sta gameBanks+$01
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$030
	sta gameBanks+$03
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$050
	sta gameBanks+$05
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$070
	sta gameBanks+$07
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$090
	sta gameBanks+$09
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$0B0
	sta gameBanks+$0B
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$0D0
	sta gameBanks+$0D
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$0F0
	sta gameBanks+$0F
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$110
	sta gameBanks+$11
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$130
	sta gameBanks+$13
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$150
	sta gameBanks+$15
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$170
	sta gameBanks+$17
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$190
	sta gameBanks+$19
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$1B0
	sta gameBanks+$1B
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$1D0
	sta gameBanks+$1D
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$1F0
	sta gameBanks+$1F
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$000
	sta gameBanks+$00
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$020
	sta gameBanks+$02
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$040
	sta gameBanks+$04
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$060
	sta gameBanks+$06
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$080
	sta gameBanks+$08
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$0A0
	sta gameBanks+$0A
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$0C0
	sta gameBanks+$0C
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$0E0
	sta gameBanks+$0E
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$100
	sta gameBanks+$10
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$120
	sta gameBanks+$12
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$140
	sta gameBanks+$14
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$160
	sta gameBanks+$16
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$180
	sta gameBanks+$18
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$1A0
	sta gameBanks+$1A
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$1C0
	sta gameBanks+$1C
	iny
	lda [destLo], y
	sta CONFIGWRITEBANK+$1E0
	sta gameBanks+$1E
rts



PrintBanks:
	PrintString "\n0 1 2 3 4 5 6 7 8 9 A B C D E F\tBanks2\t    Banks3\n"

	ldx #$0001
	ldy #$0010

__PrintBanks1:
	lda gameBanks, x
	sta errorCode
	PrintHexNum errorCode
	inx
	inx
	dey
	bne __PrintBanks1

	PrintString "\t"

	ldx #$0008
	ldy #$0004

__PrintBanks2:
	lda gameBanks, x
	sta errorCode
	PrintHexNum errorCode
	inx
	inx
	dey
	bne __PrintBanks2

	PrintString "    "

	ldx #$0018
	ldy #$0004

__PrintBanks3:
	lda gameBanks, x
	sta errorCode
	PrintHexNum errorCode
	inx
	inx
	dey
	bne __PrintBanks3
rts



; ************************** Log error output **************************

LogScreen:
	FindFile "LOG.TXT"

	lda #$FF				; load WRAM text buffer address ($00F7FF = $7EF7FF)
	sta $2181
	lda #$F7
	sta $2182
	lda #$00
	sta $2183

	ldx #$0000

Copy2bppBuffer:
	lda $2180				; read byte (address is incremented automatically)
	lsr a					; reconvert our hi-res tile data to plain ASCII characters
	sta LogBuffer, x			; put it to the log buffer
	inx					; increment counter
	inx					; skip a byte, to be filled during 4bpp loop
	cpx #$0800				; read 1024 bytes [sic, because of double "inx"]
	bne Copy2bppBuffer

	ldx #$0000

Copy4bppBuffer:
	lda $2180				; read byte (address has reached the 4bpp buffer by now)
	lsr a
	inx					; skip byte written during 2bpp loop
	sta LogBuffer, x
	inx					; increment counter
	cpx #$0800				; after another 1024 bytes, we're done :-)
	bne Copy4bppBuffer

	lda #<LogBuffer
	sta sourceLo
	lda #>LogBuffer
	sta sourceHi
	lda #$7E
	sta sourceBank

	lda #kSourceWRAM
	sta sourceType

	jump jCardWriteFile
rts



; ************************ Copier header checks ************************

SWCHeaderCheck:					; Super WildCard headers contain "AABB04" (in hex) at offset $08-$0A
	lda sectorBuffer1+$0008
	cmp #$AA
	bne SWCHeaderNotFound
	lda sectorBuffer1+$0009
	cmp #$BB
	bne SWCHeaderNotFound
	lda sectorBuffer1+$000A
	cmp #$04
	bne SWCHeaderNotFound

SWCHeaderFound:
	PrintString "SWC Header"
	lda #$01
	sta headerType

SWCHeaderNotFound:

rts



GD3HeaderCheck:
	lda sectorBuffer1+$0000			; check for "GAME"
	cmp #$47
	bne GD3HeaderNotFound
	lda sectorBuffer1+$0001
	cmp #$41
	bne GD3HeaderNotFound
	lda sectorBuffer1+$0002
	cmp #$4D
	bne GD3HeaderNotFound
	lda sectorBuffer1+$0003
	cmp #$45
	bne GD3HeaderNotFound

GD3HeaderFound:
	PrintString "GD3 Header"
	lda #$02
	sta headerType

GD3HeaderNotFound:

rts



; ************************ Show loading message ************************

ShowLoadingMsg:
	lda #$FF				; hide cursor
	sta cursorX
	lda #$F0
	sta cursorY

	stz scrollY				; make sure prior scrolling won't affect string position
	stz scrollYCounter
	stz scrollYUp
	stz scrollYDown
	stz speedCounter
	stz speedScroll

	jump jPrintClearScreen

	SetCursorPos 11, 11
	PrintString "Loading ..."
rts



; ************************** Wait for Hblank ***************************

WaitHblank:
	pha

-	lda $4212
	and #%01000000
	cmp #%01000000
	bne -

	pla
rts
