.inesprg 4 ;04 x 16k prg bank 64KB = 4x16KB 8x8KB .ineschr 0 ;no chr bank .inesmir 1 ; VERTICAL mirroring .inesmap 2 ;uxrom .include "variables.h" .bank 0 .org $8000 .incbin "loadertop.bit" ;;BOOT FPGA CONFIG FILE xc2s30 = 44KB of 48KB fpga = 42096 bytes .bank 6 .org $8000 .incbin "powerpak.nes" ;;GRAPHICS FILE 4KB .incbin "powerpak.nes" ;;GRAPHICS FILE 4KB .bank 7 ;;LAST BANK OF FLASH ROM 8KB .org $E000 ;16KB 8KB banks ;0 0/1 - fpga config 16KB ;1 2/3 - fpga config 16KB ;2 4/5 - fpga config 12KB ;3 6/7 - chr in first 8KB, boot code in last 8KB ;--------------------Set Up Program--------------------: ;------------------------------------------------------: MESSAGETABLE .dw PP,NOCARD,NOTREADY,FORMAT,RERR,WERR,NOTFOUND,LOADDIR,LOADRAM,GG,WEBSITE,STARTG,LOADGAME,HEADER,DUDE,SAVERAM,CFBUSY PP: .db " PowerPak " NOCARD: .db " Card Error - No Card Found " NOTREADY: .db " Card Error - Not Ready " FORMAT: .db " Bad Format - Use FAT16/FAT32" RERR: .db " Fatal Card Read Error " WERR: .db " Fatal Card Write Error " NOTFOUND: .db " File Not Found " LOADDIR: .db " Loading Directory... " LOADRAM: .db " Load Battery RAM " GG: .db " Game Genie Codes " WEBSITE: .db " www.retrousb.com " STARTG: .db " Start Game " LOADGAME: .db " Loading Game... " HEADER: .db " Bad iNES Header " DUDE: .db " Say NO to DiskDude " SAVERAM: .db " Saving Battery RAM... " CFBUSY: .db " Card Busy " LOGO1: .db $80, $81, $82, $83, $84, $85, $86, $87 LOGO2: .db $90, $91, $92, $93, $94, $95, $96, $97 LOGO3: .db $A0, $A1, $A2, $A3, $A4, $A5, $A6, $A7 LOGO4: .db $B0, $B1, $B2, $B3, $B4, $B5, $B6, $B7 LOGO5: .db $C0, $C1, $C2, $C3, $C4, $C5, $C6, $C7 LOGO6: .db $D0, $D1, $D2, $D3, $D4, $D5, $D6, $D7 LOGO7: .db $E0, $E1, $E2, $E3, $E4, $E5, $E6, $E7 LOGO8: .db $F0, $F1, $F2, $F3, $F4, $F5, $F6, $F7 IRQ: rti NMI: ;backup registers php ;push status pha ;push a tya pha ;push y txa pha ;push x lda #%00000110 ;graphics off sta $2001 ;do graphics updates jsr PrintLine MoveSprite: ;move sprite 0 lda $2002 lda #$3F sta $2003 lda #$10 sta $2003 lda cursorY ; initialize Sprite 0 = cursor sec sbc #$01 sta $2004 ; Y coordinate lda #$10 sta $2004 ; Pattern number lda #$03 sta $2004 ; color/attributes CHANGE ME cursor color lda cursorX sta $2004 ; X coordinate SetScroll: lda #%10001000 ;nmi on sta $2000 lda #%00011110 ;4 sprites on, 3 background on sta $2001 lda $2002 lda #$00 sta $2006 sta $2006 sta $2005 ;scroll x lda scrollY sta $2005 ;all nmi graphics done by here; inc frameCounter ;restore registers pla tax ;pop x pla tay ;pop y pla ;pop a plp rti DoFrame: jsr JoystickRead jsr $0404 ;go to module controller handler vector CheckCursor: ;check cursor counter, no scroll if counter=0 lda cursorYCounter cmp #$00 beq CursorDone dec cursorYCounter ;scroll = scroll + scrollUp - scrollDown DoCursorScroll: lda cursorY sec sbc cursorYUp clc adc cursorYDown sta cursorY CursorDone: CheckYScroll: ;check scroll counter, no scroll if counter=0 lda scrollYCounter beq DoYScrollDone dec scrollYCounter ;scroll = scroll - scrollUp + scrollDown DoYScroll: lda scrollY sec sbc scrollYUp clc adc scrollYDown sta scrollY cmp #$F0 ; 240 bcc DoYScrollDone ; scrollY < 240, no underflow/overflow DoYScrollOverflow: cmp #$F8 ; 248 bcs DoYScrollUnderflow ; scrollY > 248, no overflow sec sbc #$F0 ; scroll = scroll - 240 sta scrollY jmp DoYScrollDone DoYScrollUnderflow: lda scrollY sec sbc #$10 sta scrollY DoYScrollDone: rts ;---------------------------------; ScrollUp: sec lda selectedEntry sbc #$01 sta selectedEntry lda selectedEntry+1 ;go to prev entry sbc #$00 sta selectedEntry+1 lda selectedEntry cmp #$FF bne ScrollUpCheckTop lda selectedEntry+1 cmp #$FF bne ScrollUpCheckTop ;check if selectedEntry = FFFF (underflow) lda filesInDir sta selectedEntry lda filesInDir+1 sta selectedEntry+1 ;underflow, reset selectedEntry = filesInDir-1 sec lda selectedEntry sbc #$01 sta selectedEntry lda selectedEntry+1 sbc #$00 sta selectedEntry+1 lda filesInDir+1 cmp #$00 bne ScrollUpCheckTop lda filesInDir cmp #$1d bcs ScrollUpCheckTop ; check if filesInDir > 28 lda filesInDir jsr ASLA3 ;multiply by 8 for sprite height clc adc #$08 sta cursorY ; put cursor at bottom of list jmp ScrollUpCheckMiddle ScrollUpCheckTop: lda cursorY cmp #$08 bne ScrollUpCheckMiddle ;check if cursor at top lda speedCounter sta scrollYCounter ;cursor at top, scroll background, leave cursor lda speedScroll sta scrollYUp lda #$00 sta scrollYDown lda scrollY jsr LSRA3 sta printY jsr DirPrintEntry jmp ScrollUpDone ScrollUpCheckMiddle: lda speedCounter sta cursorYCounter lda speedScroll sta cursorYUp lda #$00 sta cursorYDown ScrollUpDone: rts ScrollDown: clc lda selectedEntry adc #$01 sta selectedEntry lda selectedEntry+1 ;go to next entry adc #$00 sta selectedEntry+1 lda selectedEntry cmp filesInDir bne ScrollDownCheckBottom lda selectedEntry+1 cmp filesInDir+1 bne ScrollDownCheckBottom ;check if selectedEntry = filesInDir lda #$00 sta selectedEntry sta selectedEntry+1 ;overflow, reset to 0 lda filesInDir+1 cmp #$00 bne ScrollDownCheckBottom lda filesInDir cmp #$1d bcs ScrollDownCheckBottom ; check if filesInDir > 28 lda #$00 sta cursorY ; put cursor at top of screen jmp ScrollDownCheckMiddle ScrollDownCheckBottom: lda cursorY cmp #$E0 ;= pixel 224 bne ScrollDownCheckMiddle ; check if cursor at bottom 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) lda #$00 sta scrollYUp lda scrollY jsr LSRA3 ; a = scroll div 8 sec sbc #$01 ; a = a - 1 cmp #$FF bne ScrollDownCheckBottomDone lda #$1D ; if a = ff, a = 29 ScrollDownCheckBottomDone sta printY jsr DirPrintEntry jmp ScrollDownDone ScrollDownCheckMiddle: lda speedCounter sta cursorYCounter lda speedScroll sta cursorYDown lda #$00 sta cursorYUp ScrollDownDone: rts ;--------------------Main Code-------------------------: ;------------------------------------------------------: RESET: cld sei ;turn rendering OFF lda #$00 sta $2000 ;7 vblank int, 4 screen addr, 3 sprite addr, 2 vertical wr, 10 name table addr sta $2001 ;765 bg color, 4 sprites on, 3 screen on, 2 sprite mask, 1 image mask lda #$40 sta $4017 ;disable frame IRQ ldx #$FF ;reset stack pointer txs jmp ClearRam ClearRamReturn: lda #$60 sta $0400 ;add vectors for dummy module, $60 = rts sta $0404 ;load from game genie address lda $4208 cmp #$01 beq ResetFPGAConfigured ;;fpga was configured and battery must be saved jmp ResetFPGANotConfigured ;;fpga wasnt configured, or battery not saved ResetFPGAConfigured: ; fpga is configured, poweron = 0 lda #$00 sta powerOn jmp ResetCopyFPGA ResetFPGANotConfigured: ; fpga isnt configured, poweron = 1 lda #$01 sta powerOn jmp ResetCopyFPGA ResetCopyFPGA: ;copy fpga data from rom $8000... to fpga jsr FPGACopyRom jsr WaitVBlank jsr WaitVBlank jsr WaitVBlank lda #$40 sta PRGBANK ;enable chr ram writing ;copy chr tiles from rom to chrram 8KB to ppu $0000 lda #$00 sta sourceLo sta destLo sta destHi lda #$80 sta sourceHi lda #$20 ;32*256 = 8KB sta source256 jsr CopyChrRam lda #$00 sta PRGBANK ;disable chr ram writing jsr ClearNameTable ; 00 TEXT CART 01 CF 10 RED 11 CART/RED ; blk dgr gry wht blk ye gry wht blk lrd rd drd blk lrd gry rd ;IMAGE PALETTE 3E 00 10 30 3E 28 10 30 3E 26 16 17 3E 17 10 16 ;Write image then sprite palettes 32 bytes lda $2002 ;clear 2006 latch lda #$3F sta $2006 lda #$00 sta $2006 ldx #$02 WritePalette: lda #$3E sta $2007 lda #$00 sta $2007 lda #$10 sta $2007 lda #$30 sta $2007 lda #$3E sta $2007 lda #$28 sta $2007 lda #$2D sta $2007 lda #$30 sta $2007 lda #$3E sta $2007 lda #$26 sta $2007 lda #$26 sta $2007 lda #$26 sta $2007 lda #$3E sta $2007 lda #$26 sta $2007 lda #$10 sta $2007 lda #$16 sta $2007 dex bne WritePalette ;put intro screen in name table lda #messagePP ;load message = POWERPAK sta temp jsr StrCopy lda #$05 sta printY jsr PrintLine lda #$F8 sta cursorX sta cursorY jsr RenderingOn nop nop nop nop nop nop ;nop ;nop ;nop jmp NewCFBoot ;;new card booting, skips to CardReady when done CardBootLoop: ;read status byte all good = 01010000 = $50 ; no card = 11111111 = $FF lda CARDSTATUS ;card status read cmp #$FF ;compare to 11111111 bne CheckCardReset lda #messageNOCARD ;load message = no card sta temp jsr StrCopy lda #$07 ; message position sta printY jmp ForeverLoop ;stop everything CheckCardReset: lda #$01 ; directly loads the Accumulator with 1 sta $4016 ; stores the Accumulator (1) into $4016 lda #$00 ; directly loads the Accumulator with 0 sta $4016 ; stores the Accumulator (0) into $4016 lda $4016 ; loads the info from the joystick and #$01 ; || cmp #$00 beq CardInserted ;if no button is pressed, no card reset CardReset: ;if A is pressed, do card reset lda #%00000110 ;do card sw reset sta CARDDEVICE ;in device ctl reg nop nop nop nop nop lda #%00000010 sta CARDDEVICE ;clear reset nop nop jmp CardBootLoop CardInserted: lda CARDSTATUS ;card status read sta sourceSector ;store somewhere unused and #%10000000 cmp #%10000000 ;check busy bit bne CardNotBusy CardBusy: lda #messageCARDBUSY ;load message = card busy sta temp jsr StrCopy lda #$1A sta printY lda sourceSector ;card status read sta temp jsr Byte2Str lda sourceSector+1 clc adc #$01 sta sourceSector+1 beq CardReset jmp CardBootLoop CardNotBusy: lda CARDSTATUS ;card status read sta sourceSector and #%01010000 cmp #%01010000 ;check ready bit beq CardReady CardNotReady: lda #messageNOTREADY ;load message = card not ready sta temp jsr StrCopy lda #$1A sta printY lda sourceSector ;card status read sta temp jsr Byte2Str jmp CardInserted CardReady: jmp CheckCardFormat .org $E642 GetVolumeID: lda #$00 sta destLo lda #$02 sta destHi jsr CardReadSector ;read FAT16/FAT32 Volume ID sector (partition boot record) lda $020D ;copy FAT16/FAT32 sectorsPerCluster from offset 13 sta sectorsPerCluster lda $020E ;copy FAT16/FAT32 reservedSectors from offset 14 sta reservedSectors lda $020F sta reservedSectors+1 ldx #$00 CardCopySectorsPerFat: ;copy FAT32 sectorsPerFat from offset 36 lda $0224, x sta sectorsPerFat, x inx cpx #$04 bne CardCopySectorsPerFat ldx #$00 CardCopyRootDirCluster32: ;copy FAT32 rootDirCluster from offset 44 lda $022C, x sta rootDirCluster, x inx cpx #$04 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: lda #$00 ;when FAT16, rootDirCluster = 0000 root dir is not in cluster nums sta rootDirCluster sta rootDirCluster+1 sta rootDirCluster+2 sta rootDirCluster+3 lda $0216 sta sectorsPerFat ;FAT16 copy sectorsPerFat from offset 22 lda $0217 sta sectorsPerFat+1 lda #$00 sta sectorsPerFat+2 sta sectorsPerFat+3 ;;FAT16 sectors per fat = 16 bits, in different place than FAT32 CardCopyRootDirEntries16: ;copy max root directory entries from offset 17 lda $0211 sta fat16RootSectors lda $0212 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 jsr CardLoadDir ; 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 jsr DirFindEntryNew ;"POWERPAK" dir into tempEntry lda tempEntry+$1C sta baseDirCluster lda tempEntry+$1D sta baseDirCluster+1 lda tempEntry+$1E sta baseDirCluster+2 lda tempEntry+$1F sta baseDirCluster+3 ;;;; powerpak dir found write base cluster ;if poweron = 1 ; fpga isnt configured, go to i.map ;if poweron = 0 ; fpga is configured, go to q.map lda powerOn beq LoadModuleQ LoadModuleI: lda #'I' sta findEntry jmp LoaderLoadModuleDone LoadModuleQ: lda #'Q' sta findEntry jmp LoaderLoadModuleDone LoaderLoadModuleDone: lda #' ' sta findEntry+1 sta findEntry+2 sta findEntry+3 sta findEntry+4 sta findEntry+5 sta findEntry+6 sta findEntry+7 jmp CardLoadModule ;load intro module Forever: jsr RenderingOn ForeverLoop: ;wait for nmi lda frameCounter cmp prevFrameCounter beq ForeverLoop jsr DoFrame lda frameCounter sta prevFrameCounter jmp ForeverLoop ;----------------------------; WaitVBlank: lda $2002 bpl WaitVBlank rts ;---------------------------: JoystickRead: ;**-Get Joystick Status** lda #$01 ; directly loads the Accumulator with 1 sta $4016 ; stores the Accumulator (1) into $4016 lda #$00 ; directly loads the Accumulator with 0 sta $4016 ; stores the Accumulator (0) into $4016 ldx #$08 ; loads 8 so it can loop for each byte Joyloop: lda $4016 ; loads the info from the joystick and #$03 ; || cmp #$01 ; narrows down the data rol $02 ; rotates info into memory... dex ; decrements X bne Joyloop ; loops again if not 0 lda $02 sta joystick rts ; returns to main routine ;-------------------------; ClearNameTable: lda $2002 lda #$20 sta $2006 lda #$00 sta $2006 ldx #$00 ldy #$08 ClearNameTableLoop: sta $2007 dex bne ClearNameTableLoop dey ;LAST CHANGE bne ClearNameTableLoop rts ClearSpriteRam: ;setup sprite ram lda $2002 lda #$00 sta $2003 sta $2003 lda #$ff ldx #$00 ClearSpriteRamLoop: sta $2004 inx bne ClearSpriteRamLoop rts ClearLine: ldy #$00 lda #' ' ClearLineLoop: sta printString, y iny cpy #$20 bne ClearLineLoop rts ClearFindEntry: ldx #$08 lda #' ' ClearFindEntryLoop sta findEntry, x dex cpx #$00 bne ClearFindEntryLoop rts PrintLine: lda #$00 sta printAddrLo sta printAddrHi ldx #$03 lda printY sta printAddrHi ; x256 ShiftLine: ;shift right 3x to mult x32 clc lsr printAddrHi ror printAddrLo dex bne ShiftLine lda printAddrHi clc ;add printAddr + $2000 (name table address) adc #$20 sta printAddrHi lda $2002 ;clear latch lda printAddrHi ;starting address to ppu sta $2006 lda printAddrLo sta $2006 ldx #$00 PrintChar: lda printString, x sta $2007 inx cpx #$20 bne PrintChar rts LoadLogo: lda #$03 sta printY jsr ClearLine ldx #$00 LoadLogoLineLoop: ldy #$00 LoadLogoCharLoop: lda LOGO1, x sta printString+12, y inx iny cpy #$08 bne LoadLogoCharLoop stx temp inc printY jsr PrintLine ldx temp lda printY cmp #$0B bne LoadLogoLineLoop ;;copy attributes lda $2002 ;clear latch lda #$23 ;starting address to ppu sta $2006 lda #$C0 ;$23C0 = attribute table sta $2006 lda #$55 ldx #$00 LoadLogoPaletteLoop1: ;;load yellow area first 8 rows sta $2007 inx cpx #$10 bne LoadLogoPaletteLoop1 lda #$F0 ;;load left side cart area sta $2007 sta $2007 sta $2007 sta $2007 lda #$FD ;;load right side cart area sta $2007 sta $2007 sta $2007 sta $2007 rts ;------------------------; CopyChrRam: lda #$03 ;16KB bank 3, 8KB bank 6 sta MAPPERWR lda $2002 lda destHi sta $2006 lda destLo sta $2006 ldy #$00 ;256 byte counter ldx source256 ;block counter CopyChrRamLoop: lda [sourceLo], y sta $2007 iny bne CopyChrRamLoop inc sourceHi dex bne CopyChrRamLoop rts ;-------------------------; StrCopy: asl temp ldx temp lda MESSAGETABLE, x sta sourceStrLo lda MESSAGETABLE+1, x sta sourceStrHi jsr ClearLine ldy #$00 StrCopyLoop: lda [sourceStrLo], y sta printString, y ;copy 32 text chars iny cpy #$20 bne StrCopyLoop ; ldy #$00 ; lda #' ' ; jsr StrCopyBlankLoop ; ldy #$18 ; jsr StrCopyBlankLoop rts ;StrCopyBlankLoop: ; ldx #$08 ;StrCopyBlankLoop1: ; sta printString, y ;blank 8 chars ; iny ; dex ; bne StrCopyBlankLoop1 ; rts ;----------------------------; MemCopy: ldy #$00 ;256 byte counter ldx source256 ;block counter MemCopyLoop: lda [sourceLo], y sta [destLo], y iny bne MemCopyLoop inc sourceHi inc destHi dex bne MemCopyLoop rts ;------------------------------; Long2Str: lda temp+3 and #$F0 lsr a lsr a lsr a lsr a clc adc #$30 sta printString+6 cmp #$3A bcc Long2Str2 clc lda printString+6 adc #$07 sta printString+6 Long2Str2: lda temp+3 and #$0F clc adc #$30 sta printString+7 cmp #$3A bcc Long2Str3 clc lda printString+7 adc #$07 sta printString+7 Long2Str3: lda temp+2 and #$F0 lsr a lsr a lsr a lsr a clc adc #$30 sta printString+4 cmp #$3A bcc Long2Str4 clc lda printString+4 adc #$07 sta printString+4 Long2Str4: lda temp+2 and #$0F clc adc #$30 sta printString+5 cmp #$3A bcc Short2Str clc lda printString+5 adc #$07 sta printString+5 Short2Str: lda temp+1 and #$F0 lsr a lsr a lsr a lsr a clc adc #$30 sta printString+2 cmp #$3A bcc Short2Str2 clc lda printString+2 adc #$07 sta printString+2 Short2Str2: lda temp+1 and #$0F clc adc #$30 sta printString+3 cmp #$3A bcc Byte2Str clc lda printString+3 adc #$07 sta printString+3 Byte2Str: lda temp and #$F0 lsr a lsr a lsr a lsr a clc adc #$30 sta printString+0 cmp #$3A bcc Byte2Str2 clc lda printString+0 adc #$07 sta printString+0 Byte2Str2: lda temp and #$0F clc adc #$30 sta printString+1 cmp #$3A bcc Byte2Str3 clc lda printString+1 adc #$07 sta printString+1 Byte2Str3: rts ;----------------------------; GameGenieEncodeBad: lda #$00 sta gameGenieCodes sta gameGenieCodes+1 sta gameGenieCodes+2 sta gameGenieCodes+3 sta gameGenieCodes+4 sta gameGenieCodes+5 sta gameGenieCodes+6 sta gameGenieCodes+7 rts GameGenieAddressEncode: ;ADDRESS LO/HI lda gameGenie+3, x ;n3 & 8 and #$08 sta gameGenieCodes lda gameGenie+4, x ;n4 & 7 and #$07 ora gameGenieCodes sta gameGenieCodes lda gameGenie+1, x ;n1 & 8 << 4 and #$08 jsr ASLA4 ora gameGenieCodes sta gameGenieCodes lda gameGenie+2, x ;n2 & 7 << 4 and #$07 jsr ASLA4 ora gameGenieCodes sta gameGenieCodes lda gameGenie+3, x ;n3 & 7 << 4 and #$07 jsr ASLA4 sta gameGenieCodes+1 lda gameGenie+5, x ;n5 & 7 and #$07 ora gameGenieCodes+1 sta gameGenieCodes+1 lda gameGenie+4, x ;n4 & 8 and #$08 ora gameGenieCodes+1 sta gameGenieCodes+1 lda gameGenieCodes+1 ;;enable a15=1 ora #$80 sta gameGenieCodes+1 rts GameGenieEncodeBadJump: jmp GameGenieEncodeBad GameGenieEncode: lda temp asl a asl a asl a sta temp ldx temp ; x = 0/8/16/24/32, beginning of code lda gameGenie+0, x cmp #$10 ;'_' beq GameGenieEncodeBadJump lda gameGenie+1, x cmp #$10 ;'_' beq GameGenieEncodeBadJump lda gameGenie+2, x cmp #$10 ;'_' beq GameGenieEncodeBadJump lda gameGenie+3, x cmp #$10 ;'_' beq GameGenieEncodeBadJump lda gameGenie+4, x cmp #$10 ;'_' beq GameGenieEncodeBadJump lda gameGenie+5, x cmp #$10 ;'_' beq GameGenieEncodeBadJump lda gameGenie+7, x cmp #$10 ;'_' beq GameGenie6Encode jmp GameGenie8Encode ; 0 1 2 3 4 GameGenie6Encode: ;x=source y=dest codes = addrlo/addrhi/data/compare/enable8 jsr GameGenieAddressEncode ;DATA lda gameGenie+1, x ;n1 & 7 << 4 and #$07 jsr ASLA4 sta gameGenieCodes+2 lda gameGenie+0, x ;n0 & 8 << 4 and #$08 jsr ASLA4 ora gameGenieCodes+2 sta gameGenieCodes+2 lda gameGenie+0, x ;n0 & 7 and #$07 ora gameGenieCodes+2 sta gameGenieCodes+2 lda gameGenie+5, x ;n5 & 8 and #$08 ora gameGenieCodes+2 sta gameGenieCodes+2 lda #$00 sta gameGenieCodes+3 sta gameGenieCodes+4 rts GameGenie8Encode: ;x=source y=dest codes = addrlo/addrhi/data/compare/enable8 jsr GameGenieAddressEncode lda #$FF sta gameGenieCodes+4 ;DATA lda gameGenie+1, x ;n1 & 7 << 4 and #$07 jsr ASLA4 sta gameGenieCodes+2 lda gameGenie+0, x ;n0 & 8 << 4 and #$08 jsr ASLA4 ora gameGenieCodes+2 sta gameGenieCodes+2 lda gameGenie+0, x ;n0 & 7 and #$07 ora gameGenieCodes+2 sta gameGenieCodes+2 lda gameGenie+7, x ;n7 & 8 and #$08 ora gameGenieCodes+2 sta gameGenieCodes+2 ;COMPARE lda gameGenie+7, x ;n7 & 7 << 4 and #$07 jsr ASLA4 sta gameGenieCodes+3 lda gameGenie+6, x ;n6 & 8 << 4 and #$08 jsr ASLA4 ora gameGenieCodes+3 sta gameGenieCodes+3 lda gameGenie+6, x ;n6 & 7 and #$07 ora gameGenieCodes+3 sta gameGenieCodes+3 lda gameGenie+5, x ;n5 & 8 and #$08 ora gameGenieCodes+3 sta gameGenieCodes+3 rts ASLA4: asl a asl a asl a asl a rts ASLA3: asl a asl a asl a rts LSRA3: lsr a lsr a lsr a rts ;--------------------------; ClusterToLBA: ; cluster->lba lba_addr(4) = clusterBeginLBA(4) + (cluster_number(2)-2 * sectorsPerCluster(1)) 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 ;;FAT32 all done ;lda fat32Enabled ;cmp #$01 ;beq ClusterToLBADone ;;;FIXME FAT16 add fat16RootSectors already included in clusterBeginLBA? ClusterToLBADone: rts ;-------------------------; 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 ;load fat sector lda #$02 sta destHi lda #$00 sta destLo jsr CardReadSector ;offset = offset % 512 ;offset of fat entry within loaded sector 0-511 lda sourceCluster+1 and #%00000001 sta sourceCluster+1 ; cluster+1=0 ;next cluster = [sector], offset lda #$00 sta sourceLo lda #$02 adc sourceCluster+1 ;sourceHi = 2 or 3 for which 256 byte block too look in sta sourceHi ldy sourceCluster ldx #$00 NextClusterLoop: lda [sourceLo], y sta sourceCluster, x iny inx cpx #$04 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 LoadNextSectorNum: ;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 LoadNextClusterNum rts LoadNextClusterNum: lda #$00 sta sectorCounter jsr NextCluster ;get cluster num into sourceCluster jsr ClusterToLBA ;get sector num into sourceSector rts ;----------------------------; CardWaitNotBusy: ;wait for not busy lda CARDSTATUS ;card status read and #%10000000 cmp #%10000000 ;check busy bit beq CardWaitNotBusy rts CardWaitDataReq: ;wait for not busy, ready, datareq, no error lda CARDSTATUS and #%01011000 cmp #%01011000 bne CardWaitDataReq rts CardCheckError: lda CARDSTATUS ; get card status, check for general error and #%00000001 cmp #%00000001 beq CardSectorError rts CardSectorError: lda #messageREADERR sta temp jsr StrCopy lda #$07 ;message position sta printY lda CARDERROR ;card error read sta temp jsr Byte2Str jmp Forever ;display message, stop everything CardLoadLBA: lda #$01 sta CARDSECTORCOUNT lda sourceSector sta CARDLBA0 lda sourceSector+1 sta CARDLBA1 lda sourceSector+2 sta CARDLBA2 lda sourceSector+3 ;load lba number and #%00001111 ora #%11100000 sta CARDLBA3 rts CardReadSector: jsr CardCheckError jsr CardWaitNotBusy jsr CardLoadLBA jsr CardCheckError lda #$20 sta CARDCOMMAND ;send card read sector command nop nop jsr CardCheckError jsr CardWaitDataReq lda #$00 sta sourceBytes lda #$02 sta source256 jsr CardReadBytes jsr CardCheckError CardReadSectorDone: rts CardReadBytes: ;read source256*sourceBytes bytes into ram ldx source256 ldy sourceBytes CardReadBytesLoop: lda CARDDATAREAD sta [destLo], y iny bne CardReadBytesLoop inc destHi dex bne CardReadBytesLoop rts CardReadSector16: jsr CardWaitNotBusy jsr CardLoadLBA lda #$20 sta CARDCOMMAND ;send card read sector command nop nop jsr CardCheckError jsr CardWaitDataReq ldy #$00 CardReadSector16Loop: ;read 16 bytes into ram lda CARDDATAREAD sta [destLo], y iny cpy #$10 bne CardReadSector16Loop clc lda destLo adc #$10 sta destLo lda destHi adc #$00 sta destHi rts CardReadSector496: ldx #$00 ldy #$00 CardReadSector496Loop: ;read 496 bytes into ram lda CARDDATAREAD sta [destLo], y cpy #$EF bne CardReadSector496LoopInc cpx #$01 bne CardReadSector496LoopInc jmp CardReadSector496LoopDone CardReadSector496LoopInc: iny bne CardReadSector496Loop inc destHi inx jmp CardReadSector496Loop CardReadSector496LoopDone: jsr CardCheckError CardReadSector496Done: rts ;------------------------------; CardWriteSector: jsr CardWaitNotBusy jsr CardLoadLBA lda #$30 sta CARDCOMMAND ;send card write sector command nop nop jsr CardCheckError jsr CardWaitDataReq ldy #$00 ldx #$02 CardWriteSectorLoop: ;read 512 bytes from ram to card lda [sourceLo], y sta CARDDATAWRITE iny bne CardWriteSectorLoop inc sourceHi dex bne CardWriteSectorLoop jsr CardCheckError CardWriteSectorDone: rts ;------------------------------; CardLoadDirClearEntryName: lda #$00 sta lfnFound ldy #$00 lda #$00 CardLoadDirClearEntryNameLoop: ;clear entry name //CHANGE ME 128 BYTES sta tempEntry, y iny cpy #$20 bne CardLoadDirClearEntryNameLoop rts ;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 #$02 sta destHi ; $0200 = where to put sector sta sourceEntryHi lda #$60 ; $6000 = where to put entry sta destEntryHi lda #$F8 sta cursorX sta cursorY ; cursor off screen lda #$00 sta destLo sta sourceEntryLo sta destEntryLo sta filesInDir sta filesInDir+1 sta destBank sta sectorCounter sta temp sta temp+1 sta selectedEntry sta selectedEntry+1 sta cursorYCounter sta speedCounter sta speedScroll sta scrollYCounter sta PRGBANK sta lfnFound jsr ClusterToLBA ; 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 sbc fat16RootSectors ; FAT16 sourceSector = root dir first sector => clusterLBABegin(4) - fat16RootSectors(1) 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: jsr CardReadSector ; put into dest jsr CardLoadDirClearEntryName ;clear entry name CardLoadDirLoop: ldy #$00 lda [sourceEntryLo], y ; if name[0] = 0x00, no more entries cmp #$00 beq CardLoadDirLastEntryFound jmp CardLoadDirCheckUnused CardLoadDirLastEntryFound: rts CardLoadDirCheckUnused: ldy #$00 lda [sourceEntryLo], y cmp #$E5 ; if name[0] = 0xE5, entry unused, skip bne CardLoadDirCheckLongName lda #$00 sta lfnFound jmp CardLoadDirNextEntry CardLoadDirCheckLongName: ldy #$0B lda [sourceEntryLo], y ; if flag = %00001111, long file name entry found and #$0F cmp #$0F bne CardLoadDirCheckShortName ldy #$00 lda [sourceEntryLo], y and #%10111111 ;mask off "last entry" bit cmp #$01 ; if index = 1 or 2, load name //CHANGE ME INDEX < 10 beq CardLoadDirLongName1 ; else skip entry cmp #$02 beq CardLoadDirLongName2 jsr CardLoadDirClearEntryName jmp CardLoadDirNextEntry ;//CHANGE ME USE MULTIPLY13 FUNCTION CardLoadDirLongName1: ldx #$00 ; index 1 = chars 0-12 jmp CardLoadDirLongName CardLoadDirLongName2: ldx #$0D ; index 2 = chars 13-25 jmp CardLoadDirLongName CardLoadDirLongName: lda #$00 sta tempEntry+$20 ;use as char counter //CHANGE ME ldy #$01 CardLoadDirLongNameLoop1: lda [sourceEntryLo], y ; loop thro 5 chars 1x3x5x7x9x cmp #$FF beq CardLoadDirLongNameLoop1FF sta tempEntry, x CardLoadDirLongNameLoop1FF: inx iny iny inc tempEntry+$20 ;use as char counter //CHANGE ME lda tempEntry+$20 ;use as char counter //CHANGE ME cmp #$05 bne CardLoadDirLongNameLoop1 ldy #$0E CardLoadDirLongNameLoop2: lda [sourceEntryLo], y ; loop thro 6 chars Ex10x12x14x16x18x cmp #$FF beq CardLoadDirLongNameLoop2FF sta tempEntry, x CardLoadDirLongNameLoop2FF: inx iny iny inc tempEntry+$20 ;use as char counter //CHANGE ME lda tempEntry+$20 ;use as char counter //CHANGE ME cmp #$0B bne CardLoadDirLongNameLoop2 ldy #$1C 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 #$0B lda [sourceEntryLo], y ;if flag = volume id, skip and #$08 cmp #$08 bne CardLoadDirCheckHidden jsr CardLoadDirClearEntryName lda #$00 sta lfnFound jmp CardLoadDirNextEntry CardLoadDirCheckHidden: ldy #$0B lda [sourceEntryLo], y and #$02 cmp #$02 ; if flag = 0x02, hidden, skip bne CardLoadDirCheckDir lda #$00 sta lfnFound jsr CardLoadDirClearEntryName ;clear entry name jmp CardLoadDirNextEntry CardLoadDirCheckDir: ldy #$0B lda [sourceEntryLo], y ;if flag = directory, load entry and #$10 cmp #$10 bne CardLoadDirCheckEx1 lda #$01 sta tempEntry+$1B ;$1B = dir flag //CHANGE ME jmp CardLoadDirShortName CardLoadDirCheckEx1: ldx #$00 ldy #$08 CardLoadDirCheckEx1Loop: lda [sourceEntryLo], y cmp exMatch1, x beq CardLoadDirCheckEx2 inx cpx #$04 bne CardLoadDirCheckEx1Loop lda #$00 sta lfnFound jsr CardLoadDirClearEntryName jmp CardLoadDirNextEntry ;if extension doesnt match, skip CardLoadDirCheckEx2: ldx #$00 ldy #$09 CardLoadDirCheckEx2Loop: lda [sourceEntryLo], y cmp exMatch2, x beq CardLoadDirCheckEx3 inx cpx #$04 bne CardLoadDirCheckEx2Loop lda #$00 sta lfnFound jsr CardLoadDirClearEntryName jmp CardLoadDirNextEntry ;if extension doesnt match, skip CardLoadDirCheckEx3: ldx #$00 ldy #$0A CardLoadDirCheckEx3Loop: lda [sourceEntryLo], y cmp exMatch3, x beq CardLoadDirShortName inx cpx #$04 bne CardLoadDirCheckEx3Loop lda #$00 sta lfnFound jsr CardLoadDirClearEntryName jmp CardLoadDirNextEntry ;if extension doesnt match, skip CardLoadDirShortName: clc lda filesInDir ;filesInDir++ adc #$01 sta filesInDir lda filesInDir+1 adc #$00 sta filesInDir+1 lda lfnFound cmp #$01 beq CardLoadDirLongShortNameFound CardLoadDirShortNameFound: ldy #$00 CardLoadDirShortNameLoop: ;if lfnFound = 0, copy short name lda [sourceEntryLo], y sta tempEntry, y iny cpy #$08 bne CardLoadDirShortNameLoop CardLoadDirShortFileName: lda tempEntry+$1B ;$1B = dir flag //CHANGE ME cmp #$01 beq CardLoadDirSaveEntry lda #'.' sta tempEntry+$8 ldy #$08 lda [sourceEntryLo], y ;//copy short file name sta tempEntry+$9 iny lda [sourceEntryLo], y sta tempEntry+$A iny lda [sourceEntryLo], y sta tempEntry+$B jmp CardLoadDirSaveEntry CardLoadDirLongShortNameFound: CardLoadDirSaveEntry: ldy #$1A lda [sourceEntryLo], y ;copy clusterhilo to last 4 bytes of entry ///CHANGE ME sta tempEntry+$1C iny lda [sourceEntryLo], y sta tempEntry+$1D ldy #$14 lda [sourceEntryLo], y sta tempEntry+$1E iny lda [sourceEntryLo], y sta tempEntry+$1F lda destBank ;change to entry storage bank sta PRGBANK ldy #$00 CardLoadDirSaveEntryLoop: ;copy entry to prg ram //CHANGE ME 128 bytes lda tempEntry, y sta [destEntryLo], y iny cpy #$20 bne CardLoadDirSaveEntryLoop clc lda destEntryLo ;destEntry += 32 //CHANGE ME to 128 bytes adc #$20 sta destEntryLo lda destEntryHi adc #$00 sta destEntryHi lda destEntryHi ;check if destEntry is overflowing, inc bank, destEntry=6000 cmp #$80 bne CardLoadDirClearTempEntryName lda #$60 sta destEntryHi ;reset to $6000 lda #$00 sta destEntryLo inc destBank ;increment bank num CardLoadDirClearTempEntryName: ldy #$00 lda #$00 sta lfnFound CardLoadDirClearTempEntryLoop: ;clear entry name sta tempEntry, y iny cpy #$20 bne CardLoadDirClearTempEntryLoop 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 #$04 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 ; if fat32, goto CardLoadDirSectorInc lda fat32Enabled 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 ; if sectorCounter = fat16RootSectors ; goto CardLoadDirLastEntryFound clc lda sectorCounter cmp fat16RootSectors beq CardLoadDirLastEntryFoundJmp jmp 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 isnt overflowing bne CardLoadDirLoadNextSector ;;;move to next cluster jsr NextCluster ;get cluster num into sourceCluster 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: ;check if cluster = last cluster ; if match, jmp 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: jsr ClusterToLBA ;sourceCluster -> first sourceSector lda #$00 sta sectorCounter ;reset sector counter CardLoadDirLoadNextSector: lda #$00 sta destLo ;reset sector dest sta sourceEntryLo ;reset entry source lda #$02 sta destHi sta sourceEntryHi jsr CardReadSector jmp CardLoadDirLoop ;-------------------------------------; CardLoadModule: lda #$60 sta $0404 ;module not ready, set controller vector to rts lda #$00 sta moduleReady lda #'M' sta exMatch1 sta exMatch1+1 sta exMatch1+2 sta exMatch1+3 lda #'A' sta exMatch2 sta exMatch2+1 sta exMatch2+2 sta exMatch2+3 lda #'P' sta exMatch3 sta exMatch3+1 sta exMatch3+2 sta exMatch3+3 lda baseDirCluster sta sourceCluster lda baseDirCluster+1 sta sourceCluster+1 lda baseDirCluster+2 sta sourceCluster+2 lda baseDirCluster+3 sta sourceCluster+3 jsr CardLoadDir ; powerpak dir ;-------------------; ; jsr DirPrintDir ;--------------------; ;findEntry info already loaded jsr DirFindEntryNew lda tempEntry+$1C sta sourceCluster sta mapperCluster lda tempEntry+$1D sta sourceCluster+1 sta mapperCluster+1 lda tempEntry+$1E sta sourceCluster+2 sta mapperCluster+2 lda tempEntry+$1F sta sourceCluster+3 sta mapperCluster+3 lda #$00 sta destLo lda #$04 sta destHi ;put into module ram ;find first sector jsr ClusterToLBA ;sourceCluster -> first sourceSector jsr RenderingOff ;;DEBUG REMOVE jsr CardReadSector clc lda sourceSector adc #$01 sta sourceSector 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 sectorsPerCluster cmp #$01 bne CardLoadModuleNextSector ;only one sector per cluster, go to next cluster jsr NextCluster jsr ClusterToLBA CardLoadModuleNextSector: lda #$00 sta destLo lda #$06 sta destHi jsr CardReadSector ;;;DEBUG ; lda $0400 ; sta temp ; lda $0400+1 ; sta temp+1 ; lda $0400+2 ; sta temp+2 ; lda $0400+3 ; sta temp+3 ; jsr Long2Str ; jsr PrintLine ; jsr ForeverLoop ;;;DEBUG lda #$00 sta scrollY sta scrollYCounter sta scrollYUp sta scrollYDown sta cursorYCounter sta cursorYUp sta cursorYDown lda #$F8 sta cursorX sta cursorY lda #$4C sta $0404 ;module ready, set controller vector to jmp jmp $0400 ;go to module begin ;-------------------------------------; DirPrintEntry: ;offset = temp * 32 temp << 5 ;bank num = temp+1 -> temp+2 lda selectedEntry sta sourceEntryLo lda #$00 sta sourceEntryHi sta printString sta printString+$1 ;replace with dir symbol sta printString+$1D ;empty text at end of string sta printString+$1E sta printString+$1F lda selectedEntry+$1 sta PRGBANK ldy #$05 DirPrintEntryShiftLoop: ;//CHANGE ME temp << 7 = 128 bytes clc asl sourceEntryLo rol sourceEntryHi dey bne DirPrintEntryShiftLoop clc lda #$60 adc sourceEntryHi sta sourceEntryHi ldy #$00 ;//CHANGE ME set starting char number DirPrintEntryCopyLoop: lda [sourceEntryLo], y sta printString+2, y iny cpy #$1B bne DirPrintEntryCopyLoop ;;; add dir symbol or empty symbol //CHANGE ME dir flag in new place ldy #$1B lda [sourceEntryLo], y beq DirPrintEntryDone lda #'/' sta printString+1 DirPrintEntryDone: rts DirGetEntry: ;offset = selectedEntry * 32 temp << 5 ;bank num = selectedEntry+1 lda selectedEntry sta sourceEntryLo lda #$00 sta sourceEntryHi lda selectedEntry+1 sta PRGBANK ldy #$05 DirGetEntryShiftLoop: asl sourceEntryLo rol sourceEntryHi dey bne DirGetEntryShiftLoop clc lda #$60 adc sourceEntryHi sta sourceEntryHi ldy #$00 DirGetEntryCopyLoop: lda [sourceEntryLo], y sta tempEntry, y iny cpy #$20 bne DirGetEntryCopyLoop rts DirFindEntry: lda #$00 sta selectedEntry sta selectedEntry+1 DirFindEntryLoop: jsr DirGetEntry ;;check if entry matches, only look at first 8 chars ldy #$00 DirFindEntryCharLoop: lda tempEntry, y cmp findEntry, y bne DirFindEntryNext iny cpy #$08 bne DirFindEntryCharLoop rts ;all 8 chars match DirFindEntryNext: clc lda selectedEntry adc #$01 sta selectedEntry lda selectedEntry+1 ;increment to next entry index adc #$00 sta selectedEntry+1 lda selectedEntry cmp filesInDir bne DirFindEntryLoop lda selectedEntry+1 cmp filesInDir+1 bne DirFindEntryLoop DirFindEntryFailed: lda #messageNOTFOUND sta temp jsr StrCopy lda #$1A ;FIXME message position sta printY ; jsr PrintLine ;FIXME change to 3x nops jsr FileNotFound ; nop ; nop ; nop jmp Forever ;---------------------------------; DirPrintDir: ;turn off rendering jsr RenderingOff jsr ClearNameTable ;loop thro entries 0 to 31 or 0 to filesInDir lda #$00 sta selectedEntry sta selectedEntry+1 sta printY sta destBank sta PRGBANK DirPrintDirLoop: inc printY ; go to next print line jsr DirPrintEntry ;copy dir entry to printString jsr PrintLine ;print to name table clc lda selectedEntry adc #$01 sta selectedEntry lda selectedEntry+1 ;increment to next entry index adc #$00 sta selectedEntry+1 DirPrintDir32Check: ;check if printY equal to 29, jump out lda printY cmp #$1D beq DirPrintDirLoopDone DirPrintDirFileCheck: ;check if temp/temp+1 equal to filesInDir, jump out lda selectedEntry cmp filesInDir bne DirPrintDirLoop lda selectedEntry+1 cmp filesInDir+1 bne DirPrintDirLoop DirPrintDirLoopDone: lda #$00 sta cursorX sta scrollY sta selectedEntry sta selectedEntry+1 sta scrollYCounter sta scrollYUp sta scrollYDown sta cursorYCounter sta cursorYUp sta cursorYDown sta speedCounter sta speedScroll sta destBank lda #$08 sta cursorY jsr RenderingOn rts ;------------------------------; FPGACopyRom: lda #$FF sta FPGAPROGRAM ;tell fpga its being reprogrammed lda #$00 sta MAPPERWR ;;;;SWITCH BANK TO 16KB bank 0 lda #$00 sta sourceLo ;copy FPGA from $8000 to $BFFF = 16KB lda #$80 sta sourceHi ldy #$00 ;256 byte counter ldx #$40 ;block counter $40 = 64 * 256 = 16KB FPGACopyRomLoop0: lda [sourceLo], y sta FPGADATA ;fpga data address iny bne FPGACopyRomLoop0 inc sourceHi dex bne FPGACopyRomLoop0 lda #$01 sta MAPPERWR ;;;;SWITCH BANK TO 16KB bank 1 lda #$00 sta sourceLo ;copy FPGA from $8000 to $BFFF = 16KB lda #$80 sta sourceHi ldy #$00 ;256 byte counter ldx #$40 ;block counter $40 = 64 * 256 = 16KB FPGACopyRomLoop1: lda [sourceLo], y sta FPGADATA ;fpga data address iny bne FPGACopyRomLoop1 inc sourceHi dex bne FPGACopyRomLoop1 lda #$02 sta MAPPERWR ;;;;SWITCH BANK TO 16KB bank 2 lda #$00 sta sourceLo ;copy FPGA from $8000 to $8125 lda #$80 sta sourceHi ldy #$00 ;256 byte counter ldx #$25 ;block counter 9328 more bytes= 37 * 256 = $25 FPGACopyRomLoop2: lda [sourceLo], y sta FPGADATA ;fpga data address iny bne FPGACopyRomLoop2 inc sourceHi dex bne FPGACopyRomLoop2 rts LoadPRGRam: lda #$00 sta sectorCounter sta destLo lda #$60 sta destHi lda gameCluster sta sourceCluster lda gameCluster+1 sta sourceCluster+1 lda gameCluster+2 sta sourceCluster+2 lda gameCluster+3 sta sourceCluster+3 jsr ClusterToLBA jsr CardReadSector16 ;get ines header 16bytes lda #$00 sta bankCounter sta destLo ;reset to beginning of prgram lda #$60 sta destHi LoadPRGRamLoop: lda #$00 sta destLo jsr CardReadSector496 ;get 496 bytes lda destHi sta temp jsr LoadNextSectorNum ;uses x,y,destHi,destLo lda temp sta destHi lda #$F0 sta destLo jsr CardReadSector16 ;get 16 bytes LoadPRGRamLoopCheckBank: lda destHi cmp #$80 bne LoadPRGRamLoop ;check if next bank needed, destHi=80 lda #$60 sta destHi lda #$00 sta destLo inc destBank inc bankCounter LoadPRGRamLoopCheckDone: ;check if all prg loaded lda bankCounter cmp prgSize beq LoadPRGRamDone lda destBank sta PRGBANK jmp LoadPRGRamLoop LoadPRGRamDone: rts LoadWRam: rts .org $F51F LoadCHRRam: lda chrSize ;if no chr, set to chrram cmp #$00 beq LoadCHRRamDone LoadCHRRam1: lda #$00 sta destBank sta CHRBANK sta destLo sta destHi sta bankCounter ;16 bytes already read for prg LoadCHRRamLoop: lda #$00 sta destLo lda $2002 lda destHi sta $2006 lda destLo sta $2006 jsr CardReadSector496Chr ;get 496 bytes lda destHi sta temp jsr LoadNextSectorNum lda temp sta destHi lda #$F0 sta destLo jsr CardReadSector16Chr ;get 16 bytes LoadCHRRamLoopCheckBank: lda destHi cmp #$20 bne LoadCHRRamLoop ;check if next bank needed, destHi=20 lda #$00 sta destHi sta destLo inc destBank inc bankCounter lda $2002 lda destHi sta $2006 lda destLo sta $2006 LoadCHRRamLoopCheckDone: ;check if all prg loaded lda bankCounter cmp chrSize beq LoadCHRRamDone lda destBank sta CHRBANK jmp LoadCHRRamLoop LoadCHRRamDone: lda #$02 sta destHi lda #$00 sta destLo jsr CardReadSector496 ;get 496 bytes to finish sector lda #$00 sta CHRBANK rts CardReadSector16Chr: jsr CardWaitNotBusy jsr CardLoadLBA lda #$20 sta CARDCOMMAND ;send card read sector command nop nop jsr CardCheckError jsr CardWaitDataReq ldy #$00 CardReadSector16ChrLoop: ;read 16 bytes into ram lda CARDDATAREAD sta $2007 iny cpy #$10 bne CardReadSector16ChrLoop clc lda destLo adc #$10 sta destLo lda destHi adc #$00 sta destHi rts CardReadSector496Chr: ldx #$00 ldy #$00 CardReadSector496ChrLoop: ;read 496 bytes into ram lda CARDDATAREAD sta $2007 cpy #$EF bne CardReadSector496ChrLoopInc cpx #$01 bne CardReadSector496ChrLoopInc jmp CardReadSector496ChrLoopDone CardReadSector496ChrLoopInc: iny bne CardReadSector496ChrLoop inc destHi inx jmp CardReadSector496ChrLoop CardReadSector496ChrLoopDone: jsr CardCheckError CardReadSector496ChrDone: rts LoadFPGA: ;get fpga data starting after 2 sectors lda mapperCluster sta sourceCluster lda mapperCluster+1 sta sourceCluster+1 lda mapperCluster+2 sta sourceCluster+2 lda mapperCluster+3 sta sourceCluster+3 lda #$00 sta sectorCounter sta tempEntry jsr ClusterToLBA ;cluster->sector#1 into sourceSector jsr LoadNextSectorNum ;sector#2 lda #$FF sta FPGAPROGRAM ;fpga program address LoadFPGALoop: jsr LoadNextSectorNum ;uses x,y,destHi,destLo jsr LoadFPGASector inc tempEntry lda tempEntry cmp #$53 ;$53 sectors = 83 sectors = 42496 bytes, fpga = 42096 bytes bne LoadFPGALoop rts LoadFPGASector: jsr CardWaitNotBusy jsr CardLoadLBA lda #$20 sta CARDCOMMAND ;send card read sector command nop nop jsr CardCheckError jsr CardWaitDataReq ldy #$00 ldx #$02 LoadFPGASectorLoop: ;read 512 bytes into fpga data lda CARDDATAREAD sta FPGADATA iny bne LoadFPGASectorLoop dex bne LoadFPGASectorLoop jsr CardCheckError LoadFPGASectorDone: rts LoadGameGenie: ;send 5 game genie codes, newdata/enable8mode/comparedata/addresslo/addresshi lda #$00 sta temp sta temp+1 LoadGameGenieLoop: lda temp+1 sta temp inc temp+1 jsr GameGenieEncode lda gameGenieCodes+2 sta GAMEGENIEWR ;new data lda gameGenieCodes+4 sta GAMEGENIEWR ;enable8 mode lda gameGenieCodes+3 sta GAMEGENIEWR ;compare data lda gameGenieCodes+0 sta GAMEGENIEWR ;address lo lda gameGenieCodes+1 sta GAMEGENIEWR ;address hi lda temp+1 cmp #$05 bne LoadGameGenieLoop ;;load fpga configured info lda useBattery sta GAMEGENIEWR ;new data lda #$00 sta GAMEGENIEWR ;enable8mode sta GAMEGENIEWR ;compare data lda #$08 sta GAMEGENIEWR ;address lo lda #$42 sta GAMEGENIEWR ;address hi rts LoadPrgChrSize: lda prgSize ;4x8KB 0100 sec sbc #$01 ;0011 and #$7F ;wram disabled sta PRGSIZEWR lda chrSize beq LoadPrgChrSizeChrRam lda chrSize ;4x8KB 0100 asl a ;1000 sec sbc #$01 ;0111 and #$7F ;chrram wr disabled sta CHRSIZEWR rts LoadPrgChrSizeChrRam: lda #$81 sta CHRSIZEWR ;chr size = 0, enable chrram wr rts LoadMirroring: ;send mirroring h/v/four lda mirroring sta MIRRORINGWR rts ;---------------------------: RenderingOn: ;turn screen on, display screen/sprites jsr ClearSpriteRam jsr WaitVBlank lda #%10001000 ;7 vblank nmi, 4 screen addr, 3 sprite addr, 2 vertical wr, 10 name table addr sta $2000 lda #%00011110 ;567 emphasis color BGR, 4 sprites on, 3 background on, 2 sprite clipping, 1 image clipping sta $2001 ;set scroll registers lda $2002 ;clear 2006 latch lda #$00 ;;fixme???? was #$20 sta $2006 sta $2006 sta $2005 sta $2005 rts RenderingOff: ;turn screen off jsr WaitVBlank lda $2002 ;clear 2006 latch lda #%00001000 ;7 vblank nmi, 4 screen addr, 3 sprite addr, 2 vertical wr, 10 name table addr sta $2000 lda #%00000110 ;567 emphasis color BGR, 4 sprites on, 3 background on, 2 sprite clipping, 1 image clipping sta $2001 rts ClearRam: ;clear ram variable 2KB bytes lda #$00 ldx #$00 ClearRamLoop: sta $0000, x sta $0100, x sta $0200, x sta $0300, x sta $0400, x sta $0500, x sta $0600, x sta $0700, x inx bne ClearRamLoop lda #'1' sta romVers lda #'1' sta romVers+1 lda #'2' sta romVers+2 jmp ClearRamReturn CheckCardFormat: lda #$00 sta sourceSector sta sourceSector+1 sta sourceSector+2 sta sourceSector+3 sta destLo lda #$02 sta destHi jsr CardReadSector ;read sector 0 to internal ram lda $03FE cmp #$55 bne CardFormatError ;last word check should be $55AA lda $03FF cmp #$AA bne CardFormatError lda #$01 sta fat32Enabled lda $03C2 ;format fat32 = 0x0B FAT32 cmp #$0B beq CardGoodFormat lda $03C2 ;format fat32 = 0x0C FAT32 LBA cmp #$0C beq CardGoodFormat lda #$00 sta fat32Enabled lda $03C2 ;format fat16 = 0x06 larger than 32MB cmp #$06 beq CardGoodFormat lda $03C2 ;format fat16 = 0x04 smaller than 32MB cmp #$04 beq CardGoodFormat lda $03C2 ;format fat16 = 0x0E with LBA cmp #$0E beq CardGoodFormat nop nop nop CardFormatError: lda #messageBADFORMAT sta temp jsr StrCopy ;print format error message, stop everything lda #$1A sta printY lda $03C2 ;card last word read sta temp jsr Byte2Str jmp ForeverLoop CardGoodFormat: ;fat32/fat16 partition found ldx #$00 CardCopyPartitionLBABegin: ;copy partitionLBABegin from offset 455 lda $03C6, x sta sourceSector, x sta partitionLBABegin, x inx cpx #$04 bne CardCopyPartitionLBABegin jmp GetVolumeID ;;rts CheckCardFormatFail: lda #$00 sta sourceSector sta sourceSector+1 sta sourceSector+2 sta sourceSector+3 sta destLo lda #$02 sta destHi jsr CardReadSector ;read sector 0 to internal ram FindCardPartition: lda $03FE cmp #$55 bne CardFormatErrorX ;last word check should be $55AA lda $03FF cmp #$AA bne CardFormatErrorX ldx #$00 ;;x = partition index 0, 16, 32, 48 ldy #$00 ;;y = partition number 0, 1, 2, 3 CardFormatCheckLoop: lda #$01 sta fat32Enabled lda $03C2, x ;format fat32 = 0x0B FAT32 cmp #$0B beq CardGoodFormatX lda $03C2, x ;format fat32 = 0x0C FAT32 LBA cmp #$0C beq CardGoodFormatX lda #$00 sta fat32Enabled lda $03C2, x ;format fat16 = 0x06 larger than 32MB cmp #$06 beq CardGoodFormatX lda $03C2, x ;format fat16 = 0x04 smaller than 32MB cmp #$04 beq CardGoodFormatX lda $03C2, x ;format fat16 = 0x0E with LBA cmp #$0E beq CardGoodFormatX inx inx inx inx inx inx inx inx inx inx inx inx inx inx inx inx iny cpy #$04 bne CardFormatCheckLoop CardFormatErrorX: lda #messageBADFORMAT sta temp jsr StrCopy ;print format error message, stop everything lda #$1A sta printY lda $03C2 ;card last word read sta temp jsr Byte2Str jmp ForeverLoop CardGoodFormatX: ;fat32/fat16 partition found lda #messageBADFORMAT sta temp jsr StrCopy ;print format error message, stop everything lda #$1A sta printY lda $03C2,x ;card last word read sta temp jsr Byte2Str ldy #$00 CardCopyPartitionLBABeginX: ;copy partitionLBABegin from offset 455 lda $03C6, x ;;x = partition index sta sourceSector, y sta partitionLBABegin, y inx iny cpy #$04 bne CardCopyPartitionLBABeginX jmp GetVolumeID ;;rts DirFindEntryNew: lda #$00 sta selectedEntry sta selectedEntry+1 lda selectedEntry cmp filesInDir bne DirFindEntryNewLoop lda selectedEntry+1 cmp filesInDir+1 bne DirFindEntryNewLoop jmp DirFindEntryNewFailed DirFindEntryNewLoop: jsr DirGetEntry ;;check if entry matches, only look at first 8 chars ldy #$00 DirFindEntryNewCharLoop: lda tempEntry, y cmp findEntry, y bne DirFindEntryNewNext iny cpy #$08 bne DirFindEntryNewCharLoop rts ;all 8 chars match DirFindEntryNewNext: clc lda selectedEntry adc #$01 sta selectedEntry lda selectedEntry+1 ;increment to next entry index adc #$00 sta selectedEntry+1 lda selectedEntry cmp filesInDir bne DirFindEntryNewLoop lda selectedEntry+1 cmp filesInDir+1 bne DirFindEntryNewLoop DirFindEntryNewFailed: lda #messageNOTFOUND sta temp jsr StrCopy lda #$1A sta printY FileNotFound: ldy #$00 FileNotFoundLoop: lda findEntry, y sta printString, y iny cpy #$08 bne FileNotFoundLoop jmp Forever WaitFrame: lda frameCounter WaitFrameLoop: cmp frameCounter beq WaitFrameLoop rts NewCFBoot: NewCFInserted: lda CARDSTATUS ;card status read cmp #$FF ;compare to 11111111 bne NewCFResetDone jsr WaitFrame lda #messageNOCARD ;load message = no card sta temp jsr StrCopy lda #$07 ; message position sta printY jmp ForeverLoop ;stop everything NewCFReset: ; lda #%00001110 ; sta CARDDEVICE ; jsr WaitFrame ; jsr WaitFrame ; lda #%00001010 ; sta CARDDEVICE ;;do software reset lda #$FF sta $8000 jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame lda #$00 sta $8000 jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame NewCFResetDone jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame jsr WaitFrame lda #$00 sta sourceSector+1 ;use as loop counter NewCFBusy: lda CARDSTATUS ;card status read sta sourceSector ;store somewhere unused and #%10000000 cmp #%10000000 ;check busy bit bne NewCFNotBusy lda #messageCARDBUSY ;load message = card busy sta temp jsr StrCopy lda #$1A sta printY lda sourceSector ;card status read sta temp jsr Byte2Str jsr WaitFrame lda sourceSector+1 clc adc #$01 sta sourceSector+1 cmp #30 ;;only check busy bit for 30 frames beq NewCFReset jmp NewCFBusy NewCFNotBusy: lda #$00 sta sourceSector+1 ;use as loop counter NewCFReady: lda CARDSTATUS ;card status read sta sourceSector and #%11010000 cmp #%01010000 ;check busy+ready bit beq NewCFDone NewCFNotReady: lda #messageNOTREADY ;load message = card not ready sta temp jsr StrCopy lda #$1A sta printY lda sourceSector ;card status read sta temp jsr Byte2Str jsr WaitFrame lda sourceSector+1 clc adc #$01 sta sourceSector+1 cmp #30 ;;only check ready bit for 30 frames bne NewCFReady jmp NewCFReset NewCFDone: jmp CardReady ;--------------------End Code--------------------------: ;------------------------------------------------------: .org $FFFA .dw NMI ;FFFa FFFb .dw RESET ;FFFc FFFd .dw IRQ ;FFFe FFFf