;FlashDrv v0.02 ; (C) 2007 by Brandon Wilson. All rights reserved. ; ;Allows a user to unlock Flash, retrieve the full calculator ID (including validation number), force garbage collects and defragmenting, ; and allow creation of strings, graph databases, pictures, programs, protected programs, groups, and Flash applications (up to 4 pages) ; directly in the archive. ; ;This supports all calculators from the 83+, 83+SE, 84+, and 84+SE series, all known OS and boot code versions. ; ;See the readme. You should probably assume everything is destroyed and screwed up after each call, because these are some pretty wicked ; hacks of OS routines (also because I'm lazy to re-implement them all myself). Don't worry, though...it's stable. :) ; ;v0.02 Changelog ;Most routines implemented, except: ; CreateReal ; CreateRList ; CreateCList ; CreateMatrix ;I'm lazy and these are pretty useless, so they'll probably stay unimplemented. ; ;v0.01 Changelog ;Initial release include "settings.inc" NOLIST include "ti83plus.inc" LIST include "equates.inc" include "header.asm" SEGMENT MAIN GLOBALS ON EXTERN getCertificatePage,isAValidPage,PutSApp,IGetKey,getLastArcPage,isOP1NamedType,DispHexA safeRAM1 equ appBackUpScreen safeRAM2 equ appBackUpScreen+256 safeRAM3 equ appBackUpScreen+512 StartApp: call UnlockFlash in a,(2) call DispHexA call IGetKey in a,(4) bit 3,a jr nz,$F ld hl,sSaveTheWhales ld de,appBackUpScreen ld (rclQueue),de ld bc,15 ldir ld (rclQueueEnd),de set 7,(iy+0Eh) set 2,(iy+33h) $$: B_JUMP JForceCmdNoChar sSaveTheWhales: DB "SAVE",29h,"THE",29h,"WHALES" GetVersion: ;Returns version of FlashDrv. ;Inputs: None ;Outputs: H is major version ; L is minor version ld hl,0002h or a ret UnlockFlash: ;Unlocks Flash protection. ;Inputs: None ;Outputs: Flash is unlocked ; C set if problems ;Destroys: All registers ; tempSwapArea ; Clears the screen and affects penCol/penRow, maybe others. ld hl,50 B_CALL EnoughMem ret c ld hl,9BCCh ld de,tempSwapArea ld bc,4 ldir ld hl,89F0h+35h ldi ld hl,0 add hl,sp ld a,l ld (de),a inc de ld a,h ld (de),a ld hl,sAppName ld de,progToEdit ld bc,9 ldir ld hl,unlockLocalizeHook in a,(6) B_CALL EnableLocalizeHook B_CALL ExecuteApp sAppName: DB AppName,0 unlockLocalizeHook: add a,e ld hl,tempSwapArea ld de,9BCCh ld bc,4 ldir ld de,89F0h+35h ldi ld e,(hl) inc hl ld d,(hl) ex de,hl ld sp,hl or a ret GarbageCollect: ;Force garbage collection of user archive. ;Inputs: None ;Outputs: User archive is restructured and cleaned up ; C set if problems ;Destroys: All registers ; tempSwapArea ;Notes: Does not touch application space ld hl,GCscfRet call APP_PUSH_ERRORH ld hl,9B88h ld de,tempSwapArea ld bc,4 ldir ld hl,flags+34h ldi ld hl,getCSCHook in a,(6) B_CALL EnableGetCSCHook ld hl,sTempProg rst 20h ld hl,2 B_CALL CreateProg ex de,hl inc hl inc hl ld (hl),0BBh inc hl ld (hl),0CEh ld hl,sTempProg rst 20h B_CALL ParseInp ld hl,sTempProg rst 20h B_CALL ChkFindSym B_CALL DelVarArc ld hl,tempSwapArea ld de,9B88h ld bc,4 ldir ld de,flags+34h ldi call APP_POP_ERRORH xor a jr GCret GCscfRet: scf GCret: ld hl,tempSwapArea ld de,9B88h ld bc,4 ldir ld de,flags+34h ldi ret getCSCHook: add a,e cp 1Ah jr nz,keypadScanned xor a ld a,k2 ret keypadScanned: or 1 ld a,b ret sTempProg: DB ProgObj,12h,34h,56h,78h,0 DefragmentApps: ;Defragment Flash application space. ;Inputs: None ;Outputs: Flash application space is restructured and cleaned up ; C set if problems ;Destroys: All registers ; asm_ram ;Notes: Does not touch user archive ld hl,DAscfRet call APP_PUSH_ERRORH ld hl,9B8Ch ld de,asm_ram ld bc,4 ldir ld hl,flags+34h ldi ld hl,cxCurApp ldi ld hl,homescreenHook in a,(6) B_CALL EnableHomescreenHook ld a,4Dh ld (cxCurApp),a ld a,40h B_CALL NewContext call APP_POP_ERRORH xor a jr DAret DAscfRet: scf DAret: ld hl,asm_ram ld de,9B8Ch ld bc,4 ldir ld de,flags+34h ldi ld de,cxCurApp ldi ret homescreenHook: add a,e or 1 ret GetFullCalcSerial: ;Gets full calculator serial number. ;Inputs: None ;Outputs: OP4 contains ID (two digits per byte) ; C set if problems call UnlockFlash B_CALL GetCalcSerial B_CALL OP4ToOP1 ld hl,0 ld (OP4+5),hl B_CALL GetCertificateStart ld de,0410h B_CALL FindFirstCertificateField scf ret nz call getCertificatePage inc hl B_CALL GetFieldSize ld de,OP4+5 call getCertificatePage B_CALL FlashToRam B_CALL FlashWriteDisable or a ret WriteVarData: ;Writes variable data directly to user archive. ;Inputs: ADE is destination address ; HL is source address ; BC is number of bytes to write ;Outputs: Bytes written ; C set if problems ;Notes: Only use destination addresses that are output from other calls (I don't remember why I said this, so do it) call isAValidPage ret c push af push de push bc push hl call UnlockFlash pop hl pop bc pop de pop af B_CALL WriteFlash B_CALL FlashWriteDisable or a ret BHL_plus_DE: ;Adds DE number of bytes to BHL pointer. ;Inputs: BHL is pointer ; DE is number of bytes to increment ;Outputs: BHL is new pointer bit 7,h jr nz,$F add hl,de bit 7,h ret z res 7,h set 6,h inc b ret $$: add hl,de ret CreateReal: ;Creates REAL variable directly in archive. ;Inputs: OP1 is name of variable ; OP2 is REAL variable value ;Outputs: REAL variable created ; C set if problems scf ret CreateCplx: ;Creates complex variable directly in archive. ;Inputs: OP1 is name of variable ; OP2/OP3 is complex variable value ;Outputs: Complex variable created ; C set if problems scf ret CreateRList: ;Creates real list directly in archive. ;Inputs: OP1 is name of variable ; HL is number of elements ;Outputs: BHL points to start of archived data (# of elements) ; C set if problems scf ret CreateCList: ;Creates complex list directly in archive. ;Inputs: OP1 is name of variable ; HL is number of elements ;Outputs: BHL points to start of archived data (# of elements) ; C set if problems scf ret CreateMatrix: ;Creates matrix directly in archive. ;Inputs: OP1 is name of variable ; H is number of rows ; L is number of columns ;Outputs: BHL points to start of archived data (# of rows/columns)\ ; C set if problems scf ret COMMENT ~ push hl ld de,safeRAM3 B_CALL MovFrOP1 B_CALL ChkFindSym pop hl ccf ret c push hl ld hl,0101h B_CALL CreateRMat pop bc ret c push de push hl push bc pop hl B_CALL HTimesL B_CALL HLTimes9 push hl pop bc pop hl pop de push bc ex de,hl ld de,11 B_CALL DelMem B_CALL OP4ToOP1 B_CALL ChkFindSym pop de jr CreateVar ~ CreateString: ;Creates string directly in archive. ;Inputs: OP1 is name of variable ; HL is size ;Outputs: BHL points to start of archived data (size bytes) ; C set if problems push hl ld de,safeRAM3 B_CALL MovFrOP1 B_CALL ChkFindSym pop hl ccf ret c push hl ld hl,0 B_CALL CreateStrng pop bc ret c push bc ex de,hl ld de,2 B_CALL DelMem B_CALL OP4ToOP1 B_CALL ChkFindSym pop de jr CreateVar CreateProgram: ;Creates unprotected program directly in archive. ;Inputs: OP1 is name of variable ; HL is size ;Outputs: BHL points to start of archived data (size bytes) ; C set if problems push hl ld de,safeRAM3 B_CALL MovFrOP1 B_CALL ChkFindSym pop hl ccf ret c push hl ld hl,0 B_CALL CreateProg pop bc ret c push bc ex de,hl ld de,2 B_CALL DelMem B_CALL OP4ToOP1 B_CALL ChkFindSym pop de jr CreateVar CreateProtectedProgram: ;Creates protected program directly in archive. ;Inputs: OP1 is name of variable ; HL is size ;Outputs: BHL points to start of archived data (size bytes) ; C set if problems push hl ld de,safeRAM3 B_CALL MovFrOP1 B_CALL ChkFindSym pop hl ccf ret c push hl ld hl,0 B_CALL CreateProtProg pop bc ret c push bc ex de,hl ld de,2 B_CALL DelMem B_CALL OP4ToOP1 B_CALL ChkFindSym pop de jr CreateVar CreatePic: ;Creates picture directly in archive. ;Inputs: OP1 is name of variable ;Outputs: BHL points to start of archived data (size bytes) ; C set if problems ld de,safeRAM3 B_CALL MovFrOP1 B_CALL ChkFindSym ccf ret c ld hl,02F4h push hl ld hl,0 B_CALL CreateStrng ld (hl),PictObj pop bc ret c push bc ex de,hl ld de,2 B_CALL DelMem B_CALL OP4ToOP1 ld a,PictObj ld (OP1),a B_CALL ChkFindSym pop de jr CreateVar CreateGDB: ;Creates graph database directly in archive. ;Inputs: OP1 is name of variable ; HL is size ;Outputs: BHL points to start of archived data (size bytes) ; C set if problems push hl ld de,safeRAM3 B_CALL MovFrOP1 B_CALL ChkFindSym pop hl ccf ret c push hl B_CALL CreatePict ld (hl),GDBObj pop bc ret c push bc ex de,hl ld de,2 B_CALL DelMem B_CALL OP4ToOP1 ld a,GDBObj ld (OP1),a B_CALL ChkFindSym pop de jr CreateVar CreateGroup: ;Creates group variable directly in archive. ;Inputs: OP1 is type and name of variable ; HL is full size of variable ;Outputs: BHL points to start of archived data (size bytes) ; C set if problems push hl ld de,safeRAM3 B_CALL MovFrOP1 B_CALL ChkFindSym pop hl ccf ret c push hl ld hl,0 B_CALL CreateProg ld (hl),GroupObj pop bc ret c push bc ex de,hl ld de,2 B_CALL DelMem B_CALL OP4ToOP1 ld a,GroupObj ld (OP1),a B_CALL ChkFindSym pop de ; jr CreateVar CreateVar: ;Creates variable directly in archive. ;Inputs: HL points to existing VAT entry ; DE is size of data ;Outputs: BHL points to start of archived data (size bytes) ; C set if problems push de ld de,asm_ram+15 ld bc,16 push de lddr pop hl dec hl dec hl dec hl ld (hl),03h dec hl ld (hl),85h pop bc ld hl,asm_ram+16 ld (hl),c inc hl ld (hl),b ld a,7Bh ld hl,_ArchiveVar ld de,safeRAM1 ld bc,3 B_CALL FlashToRam ld a,(safeRAM1+2) ld (safeRAM1+16),a ld hl,(safeRAM1) ld de,safeRAM1 ld bc,16 B_CALL FlashToRam ld hl,CVcode ld de,safeRAM2 ld bc,CVcodeEnd-CVcode ldir set 2,(iy+26h) res 3,(iy+26h) set 5,(iy+26h) call safeRAM2 ld hl,safeRAM3 rst 20h B_CALL ChkFindSym ex de,hl dec de dec de dec de ld hl,asm_ram+12 ld bc,3 lddr B_CALL ChkFindSym ld a,(hl) push af ex de,hl ld de,9 call BHL_plus_DE pop af call isSpecialType ld de,3 jr c,$F push bc ld a,b B_CALL GetBytePaged ld e,b pop bc ld d,0 call BHL_plus_DE ld de,1 $$: call BHL_plus_DE ld a,40h ld (cxCurApp),a xor a ret CVcode: ld hl,scfRet-CVcode+safeRAM2 in a,(6) push af call APP_PUSH_ERRORH di ld a,(safeRAM1+16) call translatePage out (6),a ld hl,(safeRAM1+8) push hl ld ix,(safeRAM1+5) ld de,$F-CVcode+safeRAM2 push de ld hl,asm_ram+15 ld de,asm_ram+16 jp (ix) $$: pop ix ld de,$F-CVcode+safeRAM2 push de jp (ix) $$: call APP_POP_ERRORH pop af out (6),a xor a ret scfRet: scf ret translatePage: ld b,a in a,(2) and 80h ld a,b jr z,$F in a,(21h) and 3 ld a,b ret nz and 3Fh ret $$: ld a,b and 1Fh ret CVcodeEnd: isSpecialType: cp PictObj scf ret z cp GDBObj scf ret z cp StrngObj scf ret z or a ret COMMENT ~ Old CreateVar code push hl xor a ld (OP1+9),a call isOP1NamedType jr nz,$F B_CALL CMPPRGNAMELEN jr CreateVarContinue $$: B_CALL ISO1NONTEMPLST jr nz,CreateVarContinue B_CALL CMPPRGNAMELEN inc a CreateVarContinue: call getEntryLenBC pop de ld hl,3 add hl,bc ret c add hl,de ret c push hl B_CALL ArcChk pop bc ld hl,(839Fh) ld a,h or l jr nz,enoughSpace ld hl,(83A1h) ld a,h ld h,l ld l,a ld d,b ld e,c or a sbc hl,de ret c enoughSpace: ;BC contains total size of block call findFreeArcSpot jr nc,$F call GarbageCollect call findFreeArcSpot ret c $$: ld (arcInfo),a ld (arcInfo+1),hl ;destination found, now just write the var header scf ret findFreeArcSpot: push bc push de ld a,(OP1) push af push bc ld bc,0 ld (freeArcBlock),bc call getLastArcPage call findFreeAppPageFromB ld a,b ld (83FFh),a pop bc ld a,8 findSpotLoop: push af ld hl,4000h B_CALL LoadAIndPaged cp 0FEh jr nz,notSwapSector goToNextSector: pop af add a,3 jr prepForNewRunThroughLoop notSwapSector: cp 0F0h jr z,isDeletedEntry cp 0FFh jr z,isFreeSpot pop af prepForNewRunThroughLoop: push hl ld hl,83FFh cp (hl) pop hl jr nc,setCarryRet inc a jr findSpotLoop isDeletedEntry: pop af push af push bc ld c,0FFh ld (arcPage),a ld (arcPtr),hl call incrementArcPtr call searchSectorForC pop bc jr z,goToNextSector pop de push af isFreeSpot: pop af ld (tempSwapArea),hl push bc push af ld a,(83FFh) ld b,a inc b pop af call findLargestArcBlockToDE ex de,hl pop bc call storeNewLargestArcBlock or a sbc hl,bc ld hl,(tempSwapArea) jr nc,enoughSpaceHere jr prepForNewRunThroughLoop setCarryRet: scf enoughSpaceHere: pop bc ld c,a ld a,b ld (OP1),a ld a,c pop de pop bc ret incrementArcPtr: scf ret searchSectorForC: scf ret findLargestArcBlockToDE: scf ret storeNewLargestArcBlock: scf ret getEntryLenBC: add a,7 ld b,0 ld c,a call isOP1NamedType ret z ld a,(OP1+1) cp 5Dh ret z ld c,9 ret ~ CreateApplication: ;Creates Flash application. ;Inputs: AHL points to entire variable data (16KB minimum) ;Outputs: Flash application is created ; C set if problems ;Notes: Maximum size for appvars is 64KB, so max size of app created by this routine is 4 pages. ld (iMathPtr4),a ld (iMathPtr5),hl ld de,appData ld bc,128 B_CALL FlashToRam ld hl,appData ld de,8080h B_CALL FindAppHeaderSubField scf ret nz inc hl inc hl ld a,(iMathPtr4) B_CALL GetBytePaged ld a,b ld (iMathPtr2),a ld d,a ;make sure B app pages are available call getLastArcPage $$: push de call findFreeAppPageFromB pop de ret c dec b dec d jr nz,$B call UnlockFlash call getLastArcPage call findFreeAppPageFromB writeAppLoop: ld a,b ld hl,4000h ld (iMathPtr3),hl ld (iMathPtr4+1),a writePageLoop: ld a,(iMathPtr4) ld hl,(iMathPtr5) ld de,appData ld bc,256 push af push hl B_CALL FlashToRam pop hl pop bc ld de,256 call BHL_plus_DE ld a,b ld (iMathPtr4),a ld (iMathPtr5),hl ld a,(iMathPtr4+1) ld hl,appData ld de,(iMathPtr3) ld bc,256 B_CALL WriteFlash ld hl,(iMathPtr3) ld bc,256 add hl,bc ld (iMathPtr3),hl bit 7,h jr z,writePageLoop ld a,(iMathPtr4+1) ld b,a dec b ld a,(iMathPtr2) dec a ld (iMathPtr2),a jr nz,writeAppLoop ld a,b di B_CALL SetFlashLowerBound B_CALL FlashWriteDisable xor a ld (9C87h),a ret findFreeAppPageFromB: push bc ld hl,4000h B_CALL LoadDEIndPaged set 7,d pop bc ld hl,10000h-800Fh add hl,de jr nz,notAppPage push bc ld hl,4000h ld de,8080h B_CALL FindAppHeaderSubField inc hl inc hl ld a,b B_CALL GetBytePaged ld c,b pop af sub c ld b,a jr findFreeAppPageFromB notAppPage: push bc ld hl,4000h B_CALL GetBytePaged inc b pop bc scf ret nz or a ret MarkVarValid: ;Marks a variable valid (so that it will be recovered on next reset). ;Inputs: OP1 contains type and name of variable ;Outputs: Variable is marked valid ;Destroys: All registers ; C set if problems call UnlockFlash B_CALL ChkFindSym ld a,b or a scf ret z ld b,0FCh B_CALL WriteAByte B_CALL FlashWriteDisable xor a ret