ca65 V2.11.0 - (C) Copyright 1998-2005 Ullrich von Bassewitz Main file : CFFA1.s Current file: CFFA1.s 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; CFFA for Apple 1 firmware - CF Interface for Apple 1/Replica 1 computers 000000r 1 ; CFFA1.s Version 1.0 - 05/22/2007 000000r 1 ; 000000r 1 ; Firmware Contributors: Email: 000000r 1 ; Dave Lyons dlyons@lyons42.com 000000r 1 ; Rich Dreher rich@dreher.net 000000r 1 ; 000000r 1 ; This firmware is designed to execute on an orginal 6502 000000r 1 ; 000000r 1 ; Tools used to build this firmware: CA65: 6502 Cross Assembler 000000r 1 ; http://www.cc65.org/ 000000r 1 ; 000000r 1 ; Here is the copyright from that tool using --version option 000000r 1 ; ca65 V2.11.0 - (C) Copyright 1998-2005 Ullrich von Bassewitz 000000r 1 ; 000000r 1 ; Example build instructions on an MSDOS based machine: 000000r 1 ;------------------------------------------------------ 000000r 1 ; Assumes you have installed the CC65 package and set your path, etc. 000000r 1 ; 000000r 1 ; 1) ca65 --cpu 6502 -l CFFA1.s 000000r 1 ; 2) ld65 -C CFFA1.cfg CFFA1.o -o CFFA1.bin 000000r 1 ; 000000r 1 ; Firmware Version History 000000r 1 ; ------------------------ 000000r 1 ; 000000r 1 ; Version 1.0: 000000r 1 ; Based on spdv6502 firmware from CFFA project 000000r 1 ; 000000r 1 000000r 1 ; For testing on an Apple II, use "-D APPLE2=1". 000000r 1 ; If the symbol is undefined, we set it to 0 here, 000000r 1 ; to target the Apple 1. 000000r 1 .ifndef APPLE2 000000r 1 APPLE2 = 0 000000r 1 .endif 000000r 1 000000r 1 DEBUG = 0 000000r 1 000000r 1 .define EQU = 000000r 1 .define TRUE 1 000000r 1 .define FALSE 0 000000r 1 000000r 1 SPACE EQU $A0 000000r 1 CR EQU $8D 000000r 1 ESC EQU $9B 000000r 1 000000r 1 CTRL EQU $40 000000r 1 000000r 1 ; Apple1 mainboard I/O address definitions 000000r 1 000000r 1 .if APPLE2 000000r 1 .else 000000r 1 KEY_CONTROL EQU $D011 000000r 1 KEY_DATA EQU $D010 000000r 1 DSP_DATA EQU $D012 000000r 1 DSP_CONTROL EQU $D013 000000r 1 APPLE1_MON EQU $FF1F 000000r 1 BASIC_WARM EQU $E2B3 000000r 1 .endif 000000r 1 000000r 1 StackBase EQU $100 000000r 1 000000r 1 ; 000000r 1 ; Firmware Version Information 000000r 1 ; 000000r 1 FIRMWARE_VER EQU $01 ; Version of this code 000000r 1 OLDEST_COMPAT_VER EQU $01 ; oldest API version we are compatible with 000000r 1 BLOCKOFFSET EQU 0 ; 0..255: LBA of first block of first partition 000000r 1 PARTITIONS32MB EQU 4 ; Number of 32MB Partitions supported. 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Slot I/O definitions 000000r 1 ; 000000r 1 .if APPLE2 000000r 1 .else 000000r 1 IOBase = $AFF0 ; Address is set by the Slot select line T, which is typically wired to $A000 4K select line from 74154 000000r 1 000000r 1 SetCSMask = IOBase+1 ; Two special strobe locations to set and clear MASK bit that is used to disable CS0 line to 000000r 1 ; the CompactFlash during the CPU read cycles 000000r 1 ClearCSMask = IOBase+2 ; that occur before every CPU write cycle. The normally innocuous read cycles were causing the SanDisk CF to double increment 000000r 1 ; during sector writes commands. 000000r 1 000000r 1 ATADevCtrl = IOBase+6 ; When writing 000000r 1 ATAAltStatus = IOBase+6 ; When reading 000000r 1 ATAData = IOBase+8 000000r 1 ATAError = IOBase+9 ; When reading 000000r 1 ATAFeature = IOBase+9 ; When writing 000000r 1 ATASectorCnt = IOBase+10 000000r 1 ATA_LBA07_00 = IOBase+11 000000r 1 ATA_LBA15_08 = IOBase+12 000000r 1 ATA_LBA23_16 = IOBase+13 000000r 1 ATA_LBA27_24 = IOBase+14 000000r 1 ATACommand = IOBase+15 ; When writing 000000r 1 ATAStatus = IOBase+15 ; When reading 000000r 1 .endif 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Zero-page RAM memory usage 000000r 1 PCL = $3A 000000r 1 PCH = $3B 000000r 1 000000r 1 LOMEM = $4A 000000r 1 HIMEM = $4C 000000r 1 000000r 1 ; ProDOS block interface locations 000000r 1 pdCommandCode = $42 000000r 1 pdUnitNumber = $43 000000r 1 pdIOBufferLow = $44 000000r 1 pdIOBufferHigh = $45 000000r 1 pdBlockNumberLow = $46 000000r 1 pdBlockNumberHigh = $47 000000r 1 000000r 1 .if APPLE2 000000r 1 MiscZPStorage = $00 000000r 1 .else 000000r 1 MiscZPStorage = $00 ; Currently approx 32 bytes used. 000000r 1 .endif 000000r 1 ; 000000r 1 ; Inputs to the high-level routines (Rename, Delete, ReadFile, WriteFile, etc) 000000r 1 ; 000000r 1 Destination = MiscZPStorage ; 2 bytes 000000r 1 Filename = Destination+2 ; 2 bytes 000000r 1 OldFilename = Filename+2 ; 2 bytes 000000r 1 Filetype = OldFilename+2 000000r 1 Auxtype = Filetype+1 ; 2 bytes 000000r 1 FileSize = Auxtype+2 ; 2 bytes 000000r 1 EntryPtr = FileSize+2 ; 2 bytes 000000r 1 ; 000000r 1 ; internal use 000000r 1 ; 000000r 1 DirectoryBlock = EntryPtr+2 ; 2 bytes - dir block # in Buffer 000000r 1 BitmapBase = DirectoryBlock+2 ; 1 byte - low byte of block number (00..FF) 000000r 1 BitmapBlock = BitmapBase+1 ; 1 byte - block currently in BitmapBuffer 000000r 1 BitmapDirty = BitmapBlock+1 000000r 1 PastLastBitmapBlock = BitmapDirty+1 ; 1 byte - low byte of block number (00..FF) 000000r 1 TotalBlocks = PastLastBitmapBlock+1 ; 2 bytes 000000r 1 UsedBlocks = TotalBlocks+2 ; 2 bytes 000000r 1 FreeBlocks = UsedBlocks+2 ; 2 bytes 000000r 1 EntryCounter = FreeBlocks+2 000000r 1 BlockIndex = EntryCounter+1 ; could easily move off of zero page 000000r 1 NameLen = BlockIndex+1 ; could easily move off of zero page 000000r 1 LineCounter = NameLen+1 ; could easily move off of zero page 000000r 1 digit_flag = LineCounter+1 ; could easily move off of zero page 000000r 1 num = digit_flag+1 ; 2 bytes - could easily move off of zero page 000000r 1 ; 000000r 1 LastMiscZPPlusOne = num+2 000000r 1 000000r 1 zpt1 = $F0 ;data at this location is saved/restored 000000r 1 MsgPointerLow = $F2 000000r 1 MsgPointerHi = $F3 000000r 1 000000r 1 InputBuffer = $0200 000000r 1 InputBuffer2 = $0280 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; ProDOS directory entry structure 000000r 1 ; 000000r 1 oFiletype = $10 000000r 1 oKeyBlock = $11 000000r 1 oBlockCount = $13 000000r 1 oFileSize = $15 000000r 1 oCreateDateTime = $18 000000r 1 oVersion = $1C 000000r 1 oMinVersion = $1D 000000r 1 oAccess = $1E 000000r 1 oAuxtype = $1F 000000r 1 oModDateTime = $21 000000r 1 oHeaderPointer = $25 000000r 1 000000r 1 kDirEntrySize = $27 000000r 1 kEntriesPerBlock = 13 000000r 1 000000r 1 oDirLinkPrevious = $00 000000r 1 oDirLinkNext = $02 000000r 1 oVolStorageType = $04 000000r 1 oVolVersion = $20 000000r 1 oVolAccess = $22 000000r 1 oVolEntryLength = $23 000000r 1 oVolEntriesPerBlock = $24 000000r 1 oVolFileCount = $25 000000r 1 oVolBitmapNumber = $27 000000r 1 oVolTotalBlocks = $29 000000r 1 000000r 1 oSubdirParentPointer = $27 000000r 1 oSubdirParentEntryNum = $29 000000r 1 oSubdirParentEntryLength = $2A 000000r 1 000000r 1 kAccessDelete = $80 000000r 1 kAccessRename = $40 000000r 1 kAccessNeedsBackup = $20 000000r 1 kAccessInvisible = $04 000000r 1 kAccessWrite = $02 000000r 1 kAccessRead = $01 000000r 1 kAccessFull = $C3 000000r 1 000000r 1 ; Storage types 000000r 1 kSeedling = $10 000000r 1 kSapling = $20 000000r 1 kTree = $30 000000r 1 kExtended = $50 000000r 1 kDirectory = $D0 000000r 1 kSubdirHeader = $E0 000000r 1 kVolume = $F0 000000r 1 kStorageTypeMask = $F0 000000r 1 000000r 1 ; Filetypes 000000r 1 kFiletypeText = $04 000000r 1 kFiletypeBinary = $06 000000r 1 kFiletypeDirectory = $0F 000000r 1 kFiletypeBASIC1 = $F1 000000r 1 kFiletypeBAS = $FC 000000r 1 kFiletypeSYS = $FF 000000r 1 000000r 1 ; other constants 000000r 1 kRootDirectoryBlock = 2 000000r 1 kCanonicalFirstBitmapBlock = 6 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 000000r 1 CFFA1_Initialized = $8700 ; $A5 = we've initialized our globals 000000r 1 CFFA1_Options = $8701 ; bit 7 = logging, bit 6 = terse menu 000000r 1 SpecialFirstBlock = $8702 ; 0 = normal, else high byte of special first-block buffer 000000r 1 DriveNumber = $8703 ; normally 0 to 3 for four 32MB partitions 000000r 1 DrvBlkCount0 = $8705 ; low byte of usable block count 000000r 1 DrvBlkCount1 = $8706 ; bits 8..15 of usable block count 000000r 1 DrvBlkCount2 = $8707 ; bits 16..23 of usable block count 000000r 1 000000r 1 API_A = $8710 000000r 1 StopAfter256FreeBlocks = $8711 000000r 1 000000r 1 FirstDirectoryBlock = $87AD ; 2 bytes - block # of first block of current directory 000000r 1 ForceRootDirectorySearch = $87AF ; bit 7 = OpenDir on main directory, ignoring PrefixDirectory 000000r 1 PrefixDirectory = $87B0 ; 16 bytes (length + up to 15 characters) 000000r 1 000000r 1 CopyOfZeroPage = $87C0 ; copy of MiscZPStorage 000000r 1 .if LastMiscZPPlusOne-MiscZPStorage > $40 000000r 1 .error "MiscZPStorage too large for CopyOfZeroPage" 000000r 1 .endif 000000r 1 StagingBuffer = $8800 000000r 1 buffer = $8A00 000000r 1 DirectoryBuffer = $8C00 000000r 1 BitmapBuffer = $8E00 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Driver constant definitions 000000r 1 ; 000000r 1 ; ProDOS request Constants 000000r 1 PRODOS_STATUS EQU $00 000000r 1 PRODOS_READ EQU $01 000000r 1 PRODOS_WRITE EQU $02 000000r 1 PRODOS_FORMAT EQU $03 000000r 1 000000r 1 ; ProDOS low-level return codes 000000r 1 PRODOS_NO_ERROR EQU $00 ; No error 000000r 1 PRODOS_BADCMD EQU $01 ; Bad Command (not implemented) 000000r 1 PRODOS_IO_ERROR EQU $27 ; I/O error 000000r 1 PRODOS_NO_DEVICE EQU $28 ; No Device Connected 000000r 1 PRODOS_WRITE_PROTECT EQU $2B ; Write Protected 000000r 1 PRODOS_BADBLOCK EQU $2D ; Invalid block number requested 000000r 1 PRODOS_OFFLINE EQU $2F ; Device off-line 000000r 1 ; ProDOS high-level return codes 000000r 1 eBadPathSyntax EQU $40 000000r 1 eDirNotFound EQU $44 000000r 1 eFileNotFound EQU $46 000000r 1 eDuplicateFile EQU $47 000000r 1 eVolumeFull EQU $48 000000r 1 eDirectoryFull EQU $49 000000r 1 eFileFormat EQU $4A 000000r 1 eBadStrgType EQU $4B 000000r 1 eFileLocked EQU $4E 000000r 1 eNotProDOS EQU $52 000000r 1 eBadBufferAddr EQU $56 000000r 1 eBakedBitmap EQU $5A 000000r 1 eUnknownBASICFormat EQU $FE 000000r 1 eUnimplemented EQU $FF 000000r 1 000000r 1 ; ATA Commands Codes 000000r 1 ATACRead EQU $20 000000r 1 ATACWrite EQU $30 000000r 1 ATAIdentify EQU $EC 000000r 1 ATASetFeature EQU $EF 000000r 1 Enable8BitTransfers EQU $01 000000r 1 000000r 1 ; Constants for Wait 000000r 1 ; Constant = (Delay[in uS]/2.5 + 2.09)^.5 - 2.7 000000r 1 WAIT_100ms EQU 197 000000r 1 WAIT_40ms EQU 124 000000r 1 WAIT_100us EQU 4 000000r 1 000000r 1 .listbytes unlimited 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; CFFA1 firmware entry jump table 000000r 1 ; 000000r 1 .if APPLE2 000000r 1 Origin = $0A00 ; CALL 2560 000000r 1 .else 000000r 1 Origin = $9000 ; CALL -28672 000000r 1 .endif 000000r 1 .ORG Origin 009000 1 009000 1 4C D6 90 jmp MenuExitToMonitor ; $9000 009003 1 4C DC 90 jmp MenuExitToBASIC ; $9003 009006 1 4C E2 90 jmp Menu ; $9006 009009 1 4C 98 A7 jmp CFBlockDriver ; $9009 00900C 1 4C 15 90 jmp CFFA1_API ; $900C 00900F 1 ; add jumps to new functionallity here.... 00900F 1 EA nop 009010 1 EA nop 009011 1 EA nop 009012 1 EA nop 009013 1 EA nop 009014 1 EA nop 009015 1 009015 1 ;------------------------------------------------------------------------------ 009015 1 ; CFFA1_API -- Entry point for assembly programs to call CFFA1 ROM. 009015 1 ; 009015 1 ; ldx #Command 009015 1 ; jsr API 009015 1 ; 009015 1 ; Result: CLC, A = 0 for success 009015 1 ; SEC, A = error code 009015 1 CFFA1_API: 009015 1 E0 30 cpx #dispatchAPI_end-dispatchAPI 009017 1 B0 1A bcs @badCommand 009019 1 8D 10 87 sta API_A 00901C 1 20 86 90 jsr InitializeGlobals 00901F 1 20 27 90 jsr @DispatchAPI 009022 1 B0 12 bcs @exit 009024 1 A9 00 lda #0 009026 1 60 rts 009027 1 009027 1 @DispatchAPI: 009027 1 BD 38 90 lda dispatchAPI+1,x 00902A 1 48 pha 00902B 1 BD 37 90 lda dispatchAPI,x 00902E 1 48 pha 00902F 1 AD 10 87 lda API_A 009032 1 60 rts 009033 1 009033 1 @badCommand: 009033 1 A9 01 lda #PRODOS_BADCMD 009035 1 38 sec 009036 1 @exit: 009036 1 60 rts 009037 1 009037 1 ; 009037 1 ; These API_* routines return with SEC/A=error, or with CLC (A=anything). 009037 1 ; The dispatcher takes care of setting A=0 in the no-error case. 009037 1 ; 009037 1 dispatchAPI: 009037 1 6A 90 .word API_Version-1 ; $00 009039 1 70 90 .word API_Menu-1 ; $02 00903B 1 75 90 .word API_DisplayError-1 ; $04 00903D 1 66 90 .word API_Reserved-1 ; $06 00903F 1 66 90 .word API_Reserved-1 ; $08 009041 1 66 90 .word API_Reserved-1 ; $0A 009043 1 66 90 .word API_Reserved-1 ; $0C 009045 1 66 90 .word API_Reserved-1 ; $0E 009047 1 009047 1 9A 9A .word API_OpenDir-1 ; $10 009049 1 5C 9B .word API_ReadDir-1 ; $12 00904B 1 F2 A5 .word API_FindDirEntry-1 ; $14 00904D 1 66 90 .word API_Reserved-1 ; $16 00904F 1 66 90 .word API_Reserved-1 ; $18 009051 1 66 90 .word API_Reserved-1 ; $1A 009053 1 66 90 .word API_Reserved-1 ; $1C 009055 1 66 90 .word API_Reserved-1 ; $1E 009057 1 009057 1 42 A2 .word API_WriteFile-1 ; $20 009059 1 55 9D .word API_ReadFile-1 ; $22 00905B 1 85 A3 .word API_SaveBASICFile-1 ; $24 00905D 1 48 A3 .word API_LoadBASICFile-1 ; $26 00905F 1 0E A0 .word API_Rename-1 ; $28 009061 1 94 A0 .word API_Delete-1 ; $2A 009063 1 D1 A3 .word API_NewDirectoryAtRoot-1 ; $2C 009065 1 7A 90 .word API_FormatDrive-1 ; $2E 009067 1 dispatchAPI_end: 009067 1 009067 1 API_Reserved: 009067 1 A9 FF lda #eUnimplemented 009069 1 38 sec 00906A 1 60 rts 00906B 1 00906B 1 API_Version: 00906B 1 A2 01 ldx #FIRMWARE_VER 00906D 1 A0 01 ldy #OLDEST_COMPAT_VER 00906F 1 18 clc 009070 1 60 rts 009071 1 009071 1 API_Menu: 009071 1 20 E2 90 jsr Menu 009074 1 18 clc 009075 1 60 rts 009076 1 009076 1 API_DisplayError: 009076 1 20 18 97 jsr DisplayError 009079 1 18 clc 00907A 1 60 rts 00907B 1 00907B 1 API_FormatDrive: 00907B 1 C0 77 cpy #$77 ; extra magic number to avoid accidental formatting 00907D 1 D0 03 bne @fail 00907F 1 4C A5 A4 jmp FormatDrive 009082 1 @fail: 009082 1 A9 01 lda #PRODOS_BADCMD 009084 1 38 sec 009085 1 60 rts 009086 1 009086 1 ;------------------------------------------------------------------------------ 009086 1 ; InitializeGlobals 009086 1 ; 009086 1 ; Preserves: X, Y. 009086 1 ; 009086 1 InitializeGlobals: 009086 1 A9 A5 lda #$A5 009088 1 CD 00 87 cmp CFFA1_Initialized 00908B 1 F0 11 beq @initialized 00908D 1 8D 00 87 sta CFFA1_Initialized 009090 1 ; 009090 1 ; Set up additional globals here. 009090 1 ; 009090 1 A9 00 lda #0 009092 1 8D 01 87 sta CFFA1_Options 009095 1 8D 03 87 sta DriveNumber 009098 1 8D B0 87 sta PrefixDirectory ;empty prefix = use root of volume 00909B 1 8D AF 87 sta ForceRootDirectorySearch 00909E 1 @initialized: 00909E 1 60 rts 00909F 1 00909F 1 ;------------------------------------------------------------------------------ 00909F 1 ; 00909F 1 ; Set up break handler vector for Apple1 ROM vector at: $100 00909F 1 ; 00909F 1 SetUpBreakHandler: 00909F 1 .if APPLE2 00909F 1 .else 00909F 1 A9 4C lda #$4C 0090A1 1 8D 00 01 sta $100 0090A4 1 A9 AF lda #BreakHandler 0090AB 1 8D 02 01 sta $102 0090AE 1 .endif 0090AE 1 60 rts 0090AF 1 0090AF 1 ;------------------------------------------------------------------------------ 0090AF 1 ; 0090AF 1 ; Break/IRQ handler 0090AF 1 ; 0090AF 1 .if APPLE2 0090AF 1 .else 0090AF 1 BreakHandler: 0090AF 1 68 pla 0090B0 1 48 pha ;**irq handler 0090B1 1 0A asl 0090B2 1 0A asl 0090B3 1 0A asl 0090B4 1 30 0F bmi @Break ;test for break 0090B6 1 0090B6 1 @IRQ: 0090B6 1 20 8C 96 jsr DispString 0090B9 1 49 52 51 2E .byte "IRQ...",CR,CR,0 0090BD 1 2E 2E 8D 8D 0090C1 1 00 0090C2 1 4C 1F FF jmp APPLE1_MON 0090C5 1 0090C5 1 @Break: 0090C5 1 20 8C 96 jsr DispString 0090C8 1 42 52 45 41 .byte "BREAK...",CR,CR,0 0090CC 1 4B 2E 2E 2E 0090D0 1 8D 8D 00 0090D3 1 4C 1F FF jmp APPLE1_MON 0090D6 1 .endif 0090D6 1 0090D6 1 ;------------------------------------------------------------------------------ 0090D6 1 ; 0090D6 1 ; Run the menu, and then exit to the monitor. 0090D6 1 ; 0090D6 1 MenuExitToMonitor: 0090D6 1 20 E2 90 jsr Menu 0090D9 1 .if APPLE2 0090D9 1 jmp $FF69 ; Apple II monitor 0090D9 1 .else 0090D9 1 4C 1F FF jmp APPLE1_MON 0090DC 1 .endif 0090DC 1 0090DC 1 ;------------------------------------------------------------------------------ 0090DC 1 ; 0090DC 1 ; Run the menu, and then exit to BASIC. 0090DC 1 ; 0090DC 1 MenuExitToBASIC: 0090DC 1 20 E2 90 jsr Menu 0090DF 1 .if APPLE2 0090DF 1 jmp $E003 0090DF 1 .else 0090DF 1 4C B3 E2 jmp BASIC_WARM 0090E2 1 .endif 0090E2 1 0090E2 1 0090E2 1 ;------------------------------------------------------------------------------ 0090E2 1 ; CFFA1 interactive menu 0090E2 1 ; 0090E2 1 Menu: 0090E2 1 20 40 91 jsr SaveZeroPage 0090E5 1 20 86 90 jsr InitializeGlobals 0090E8 1 20 9F 90 jsr SetUpBreakHandler 0090EB 1 MenuAgain: 0090EB 1 20 4B 91 jsr DisplayMenu 0090EE 1 20 53 98 jsr WaitForKey ; wait for user to press any key 0090F1 1 20 4A 98 jsr DispChar ; display char user typed 0090F4 1 20 8C 96 jsr DispString 0090F7 1 8D 8D 00 .byte CR,CR,0 0090FA 1 0090FA 1 29 7F and #$7F ; strip high bit before comparison 0090FC 1 20 81 96 jsr UppercaseA 0090FF 1 A2 FC ldx #-4 009101 1 @FindMenuItem: 009101 1 E8 inx 009102 1 E8 inx 009103 1 E8 inx 009104 1 E8 inx 009105 1 BC 4E 92 ldy MenuChoices,x 009108 1 F0 18 beq UnknownMenuChoice 00910A 1 DD 4E 92 cmp MenuChoices,x 00910D 1 D0 F2 bne @FindMenuItem 00910F 1 00910F 1 BD 51 92 lda MenuChoices+3,x 009112 1 85 01 sta Destination+1 009114 1 BD 50 92 lda MenuChoices+2,x 009117 1 85 00 sta Destination 009119 1 20 1F 91 jsr @DoMenuChoice 00911C 1 4C EB 90 jmp MenuAgain 00911F 1 00911F 1 @DoMenuChoice: 00911F 1 6C 00 00 jmp (Destination) 009122 1 009122 1 UnknownMenuChoice: 009122 1 20 8C 96 jsr DispString 009125 1 3F 8D 00 .byte "?",CR,0 009128 1 2C 01 87 bit CFFA1_Options 00912B 1 50 03 bvc @1 00912D 1 20 60 91 jsr DisplayOptions ; in Terse mode, display options after invalid choice 009130 1 @1: 009130 1 4C EB 90 jmp MenuAgain 009133 1 009133 1 MenuExit: 009133 1 68 pla ; discard the DoMenuChoice return address 009134 1 68 pla 009135 1 ; v v v Fall into v v v 009135 1 ;------------------------------------------------------------------------------ 009135 1 ; RestoreZeroPage 009135 1 ; 009135 1 RestoreZeroPage: 009135 1 A2 1F ldx #LastMiscZPPlusOne-MiscZPStorage-1 009137 1 @restore: 009137 1 BD C0 87 lda CopyOfZeroPage,x 00913A 1 95 00 sta MiscZPStorage,x 00913C 1 CA dex 00913D 1 10 F8 bpl @restore 00913F 1 60 rts 009140 1 009140 1 ;------------------------------------------------------------------------------ 009140 1 ; SaveZeroPage 009140 1 ; 009140 1 SaveZeroPage: 009140 1 A2 1F ldx #LastMiscZPPlusOne-MiscZPStorage-1 009142 1 @save: 009142 1 B5 00 lda MiscZPStorage,x 009144 1 9D C0 87 sta CopyOfZeroPage,x 009147 1 CA dex 009148 1 10 F8 bpl @save 00914A 1 60 rts 00914B 1 00914B 1 ;------------------------------------------------------------------------------ 00914B 1 DisplayMenu: 00914B 1 2C 01 87 bit CFFA1_Options 00914E 1 70 03 bvs @terse 009150 1 20 60 91 jsr DisplayOptions 009153 1 @terse: 009153 1 20 8C 96 jsr DispString 009156 1 8D 43 46 46 .byte CR,"CFFA1> ",0 00915A 1 41 31 3E 20 00915E 1 00 00915F 1 60 rts 009160 1 009160 1 DisplayOptions: 009160 1 20 8C 96 jsr DispString 009163 1 8D 20 43 46 .byte CR, " CFFA1 MENU (1.0)",CR 009167 1 46 41 31 20 00916B 1 4D 45 4E 55 00916F 1 20 28 31 2E 009173 1 30 29 8D 009176 1 20 2D 2D 2D .byte " ----------",CR 00917A 1 2D 2D 2D 2D 00917E 1 2D 2D 2D 8D 009182 1 20 43 20 2D .byte " C - CATALOG P - PREFIX",CR 009186 1 20 43 41 54 00918A 1 41 4C 4F 47 00918E 1 20 20 20 20 009192 1 20 20 50 20 009196 1 2D 20 50 52 00919A 1 45 46 49 58 00919E 1 8D 00919F 1 20 4C 20 2D .byte " L - LOAD N - NEW DIRECTORY",CR 0091A3 1 20 4C 4F 41 0091A7 1 44 20 20 20 0091AB 1 20 20 20 20 0091AF 1 20 20 4E 20 0091B3 1 2D 20 4E 45 0091B7 1 57 20 44 49 0091BB 1 52 45 43 54 0091BF 1 4F 52 59 8D 0091C3 1 20 53 20 2D .byte " S - SAVE (BASIC) W - WRITE FILE",CR 0091C7 1 20 53 41 56 0091CB 1 45 20 28 42 0091CF 1 41 53 49 43 0091D3 1 29 20 57 20 0091D7 1 2D 20 57 52 0091DB 1 49 54 45 20 0091DF 1 46 49 4C 45 0091E3 1 8D 0091E4 1 20 52 20 2D .byte " R - RENAME D - DELETE",CR 0091E8 1 20 52 45 4E 0091EC 1 41 4D 45 20 0091F0 1 20 20 20 20 0091F4 1 20 20 44 20 0091F8 1 2D 20 44 45 0091FC 1 4C 45 54 45 009200 1 8D 009201 1 5E 46 20 2D .byte "^F - FORMAT T - TERSE",CR 009205 1 20 46 4F 52 009209 1 4D 41 54 20 00920D 1 20 20 20 20 009211 1 20 20 54 20 009215 1 2D 20 54 45 009219 1 52 53 45 8D 00921D 1 20 42 20 2D .byte " B - READ BLOCK M - MEMORY DISPLAY",CR 009221 1 20 52 45 41 009225 1 44 20 42 4C 009229 1 4F 43 4B 20 00922D 1 20 20 4D 20 009231 1 2D 20 4D 45 009235 1 4D 4F 52 59 009239 1 20 44 49 53 00923D 1 50 4C 41 59 009241 1 8D 009242 1 ; .byte "^S - STATUS ^D - DEBUG",CR 009242 1 20 51 20 2D .byte " Q - QUIT",CR,0 009246 1 20 51 55 49 00924A 1 54 8D 00 00924D 1 60 rts 00924E 1 00924E 1 MenuChoices: 00924E 1 43 00 AF 98 .word 'C', MenuCatalog 009252 1 50 00 BB 94 .word 'P', MenuPrefix 009256 1 4C 00 C6 93 .word 'L', MenuLoadBASICOrBinaryFile 00925A 1 4E 00 9C 94 .word 'N', MenuNewDirectory 00925E 1 53 00 19 96 .word 'S', MenuSaveBASICFile 009262 1 57 00 2A 94 .word 'W', MenuWriteFile 009266 1 52 00 ED 94 .word 'R', MenuRenameFile 00926A 1 44 00 D5 94 .word 'D', MenuDeleteFile 00926E 1 06 00 61 95 .word 'F'-CTRL, MenuFormat 009272 1 54 00 36 95 .word 'T', MenuToggleTerse 009276 1 42 00 90 92 .word 'B', MenuReadBlock 00927A 1 4D 00 C5 92 .word 'M', MenuDisplayMemory 00927E 1 04 00 29 95 .word 'D'-CTRL, MenuToggleDebug 009282 1 13 00 64 93 .word 'S'-CTRL, MenuGetStatus 009286 1 51 00 33 91 .word 'Q', MenuExit 00928A 1 .if DEBUG 00928A 1 .word 'Z'-CTRL, MenuWriteTwelveFiles 00928A 1 .endif 00928A 1 3F 00 60 91 .word '?', DisplayOptions 00928E 1 00 00 .word 0 009290 1 009290 1 ;------------------------------------------------------------------------------ 009290 1 ; MenuReadBlock 009290 1 ; 009290 1 MenuReadBlock: 009290 1 20 8C 96 jsr DispString 009293 1 52 45 41 44 .byte "READ BLOCK: $",0 009297 1 20 42 4C 4F 00929B 1 43 4B 3A 20 00929F 1 24 00 0092A1 1 20 2F 96 jsr InputNumberAX 0092A4 1 90 01 bcc @notEmpty 0092A6 1 60 rts 0092A7 1 @notEmpty: 0092A7 1 20 19 A7 jsr UseBuffer 0092AA 1 20 90 A7 jsr ReadBlockAX 0092AD 1 B0 13 bcs @err 0092AF 1 A9 8A lda #>buffer 0092B1 1 A2 00 ldx #512 0092B9 1 A2 00 ldx #<512 0092BB 1 85 0A sta FileSize+1 0092BD 1 86 09 stx FileSize 0092BF 1 4C FE 92 jmp DisplayMemory 0092C2 1 @err: 0092C2 1 4C 18 97 jmp DisplayError 0092C5 1 0092C5 1 ;------------------------------------------------------------------------------ 0092C5 1 ; MenuDisplayMemory 0092C5 1 ; 0092C5 1 MenuDisplayMemory: 0092C5 1 20 8C 96 jsr DispString 0092C8 1 53 54 41 52 .byte "START: $",0 0092CC 1 54 3A 20 24 0092D0 1 00 0092D1 1 20 2F 96 jsr InputNumberAX 0092D4 1 B0 15 bcs @exit 0092D6 1 85 01 sta Destination+1 0092D8 1 86 00 stx Destination 0092DA 1 0092DA 1 20 8C 96 jsr DispString 0092DD 1 20 20 45 4E .byte " END: $",0 0092E1 1 44 3A 20 24 0092E5 1 00 0092E6 1 20 2F 96 jsr InputNumberAX 0092E9 1 90 01 bcc @go 0092EB 1 @exit: 0092EB 1 60 rts 0092EC 1 @go: 0092EC 1 A8 tay ; compute FileSize = (AX - Destination) + 1 0092ED 1 8A txa 0092EE 1 38 sec 0092EF 1 E5 00 sbc Destination 0092F1 1 AA tax 0092F2 1 98 tya 0092F3 1 E5 01 sbc Destination+1 0092F5 1 A8 tay 0092F6 1 E8 inx 0092F7 1 D0 01 bne @1 0092F9 1 C8 iny 0092FA 1 @1: 0092FA 1 86 09 stx FileSize 0092FC 1 84 0A sty FileSize+1 0092FE 1 ; v v v fall into v v v 0092FE 1 ;------------------------------------------------------------------------------ 0092FE 1 ; DisplayMemory 0092FE 1 ; 0092FE 1 ; Input: Destination (starting address), FileSize (number of bytes to display) 0092FE 1 ; 0092FE 1 DisplayMemory: 0092FE 1 20 5A 9A jsr ResetLineCount 009301 1 009301 1 A5 09 lda FileSize 009303 1 D0 02 bne @noBorrow 009305 1 C6 0A dec FileSize+1 009307 1 @noBorrow: 009307 1 C6 09 dec FileSize 009309 1 009309 1 @line: 009309 1 20 1F 93 jsr DisplayOneLine 00930C 1 B0 0E bcs @exit 00930E 1 A5 09 lda FileSize 009310 1 E9 07 sbc #7 ; subtracts 8, since carry is clear 009312 1 85 09 sta FileSize 009314 1 A5 0A lda FileSize+1 009316 1 E9 00 sbc #0 009318 1 85 0A sta FileSize+1 00931A 1 B0 ED bcs @line 00931C 1 @exit: 00931C 1 4C 43 98 jmp PressSpaceAndDispCR ;SEC if we have already had ESC=abort 00931F 1 00931F 1 DisplayOneLine: 00931F 1 A5 01 lda Destination+1 009321 1 20 2A 98 jsr DispByte 009324 1 A5 00 lda Destination 009326 1 20 2A 98 jsr DispByte 009329 1 A9 BA lda #':'+$80 00932B 1 20 4A 98 jsr DispChar 00932E 1 A0 00 ldy #0 009330 1 @byte: 009330 1 B1 00 lda (Destination),y 009332 1 20 2A 98 jsr DispByte 009335 1 20 3F 98 jsr DispSpace 009338 1 C8 iny 009339 1 C0 08 cpy #8 00933B 1 90 F3 bcc @byte 00933D 1 00933D 1 20 3F 98 jsr DispSpace 009340 1 A0 00 ldy #0 009342 1 @char: 009342 1 B1 00 lda (Destination),y 009344 1 20 59 93 jsr DisplayCharPrintable 009347 1 C8 iny 009348 1 C0 08 cpy #8 00934A 1 90 F6 bcc @char 00934C 1 00934C 1 98 tya 00934D 1 18 clc 00934E 1 65 00 adc Destination 009350 1 85 00 sta Destination 009352 1 90 02 bcc @samePage 009354 1 E6 01 inc Destination+1 009356 1 @samePage: 009356 1 4C 5F 9A jmp PauseEveryNLines 009359 1 009359 1 DisplayCharPrintable: 009359 1 09 80 ora #$80 00935B 1 C9 A0 cmp #SPACE 00935D 1 B0 02 bcs @ok 00935F 1 A9 AE lda #'.'+$80 009361 1 @ok: 009361 1 4C 4A 98 jmp DispChar 009364 1 009364 1 009364 1 ;------------------------------------------------------------------------------ 009364 1 ; MenuGetStatus 009364 1 ; 009364 1 ; Prompt for drive number, call Status, and display the block count. 009364 1 ; 009364 1 MenuGetStatus: 009364 1 20 8C 96 jsr DispString 009367 1 44 52 49 56 .byte "DRIVE # (0-3): $",0 00936B 1 45 20 23 20 00936F 1 28 30 2D 33 009373 1 29 3A 20 24 009377 1 00 009378 1 20 2F 96 jsr InputNumberAX 00937B 1 B0 40 bcs @exit 00937D 1 8E 03 87 stx DriveNumber 009380 1 009380 1 20 8C 96 jsr DispString 009383 1 42 4C 4F 43 .byte "BLOCK COUNT FOR DRIVE ",0 009387 1 4B 20 43 4F 00938B 1 55 4E 54 20 00938F 1 46 4F 52 20 009393 1 44 52 49 56 009397 1 45 20 00 00939A 1 AD 03 87 lda DriveNumber 00939D 1 09 30 ora #'0' 00939F 1 20 4A 98 jsr DispChar 0093A2 1 0093A2 1 A9 00 lda #PRODOS_STATUS 0093A4 1 85 42 sta pdCommandCode 0093A6 1 20 98 A7 jsr CFBlockDriver 0093A9 1 B0 13 bcs @error 0093AB 1 0093AB 1 20 8C 96 jsr DispString 0093AE 1 20 3D 20 00 .byte " = ",0 0093B2 1 98 tya 0093B3 1 20 25 98 jsr DispByteWithDollarSign 0093B6 1 8A txa 0093B7 1 20 2A 98 jsr DispByte 0093BA 1 20 48 98 jsr DispCR 0093BD 1 0093BD 1 @exit: 0093BD 1 60 rts 0093BE 1 0093BE 1 @error: 0093BE 1 20 8C 96 jsr DispString 0093C1 1 8D 00 .byte CR,0 0093C3 1 4C 18 97 jmp DisplayError 0093C6 1 0093C6 1 ;------------------------------------------------------------------------------ 0093C6 1 ; MenuLoadBASICOrBinaryFile 0093C6 1 ; 0093C6 1 MenuLoadBASICOrBinaryFile: 0093C6 1 20 8C 96 jsr DispString 0093C9 1 20 20 20 4C .byte " LOAD FILE: ",0 0093CD 1 4F 41 44 20 0093D1 1 46 49 4C 45 0093D5 1 3A 20 00 0093D8 1 20 64 98 jsr GETLN 0093DB 1 F0 3D beq @empty 0093DD 1 0093DD 1 A2 7F ldx #127 0093DF 1 @copyName: 0093DF 1 BD 00 02 lda InputBuffer,x 0093E2 1 9D 80 02 sta InputBuffer2,x 0093E5 1 CA dex 0093E6 1 10 F7 bpl @copyName 0093E8 1 0093E8 1 A9 02 lda #>InputBuffer2 0093EA 1 A2 80 ldx #InputBuffer 00942A 1 ldx #$1000 00942A 1 ldx #<$1000 00942A 1 sta Destination+1 00942A 1 stx Destination 00942A 1 sta Auxtype+1 00942A 1 stx Auxtype 00942A 1 00942A 1 lda #>$1234 00942A 1 ldx #<$1234 00942A 1 sta FileSize+1 00942A 1 stx FileSize 00942A 1 00942A 1 lda #kFiletypeBinary 00942A 1 sta Filetype 00942A 1 00942A 1 jsr WriteFile 00942A 1 bcs @error 00942A 1 00942A 1 jsr DispString 00942A 1 .byte "Wrote file ",0 00942A 1 lda InputBuffer+1 00942A 1 jsr DispChar 00942A 1 jsr DispCR 00942A 1 00942A 1 inc InputBuffer+1 00942A 1 lda InputBuffer+1 00942A 1 cmp #'M' 00942A 1 bcc @nextFile 00942A 1 rts 00942A 1 00942A 1 @error: 00942A 1 jmp DisplayError 00942A 1 .endif 00942A 1 00942A 1 ;------------------------------------------------------------------------------ 00942A 1 ; MenuWriteFile 00942A 1 ; 00942A 1 MenuWriteFile: 00942A 1 20 8C 96 jsr DispString 00942D 1 57 52 49 54 .byte "WRITE FROM: $",0 009431 1 45 20 46 52 009435 1 4F 4D 3A 20 009439 1 24 00 00943B 1 20 2F 96 jsr InputNumberAX 00943E 1 B0 5B bcs @empty 009440 1 85 01 sta Destination+1 009442 1 86 00 stx Destination 009444 1 85 08 sta Auxtype+1 009446 1 86 07 stx Auxtype 009448 1 009448 1 20 8C 96 jsr DispString 00944B 1 20 20 20 20 .byte " LENGTH: $",0 00944F 1 4C 45 4E 47 009453 1 54 48 3A 20 009457 1 24 00 009459 1 20 2F 96 jsr InputNumberAX 00945C 1 B0 3D bcs @empty 00945E 1 85 0A sta FileSize+1 009460 1 86 09 stx FileSize 009462 1 009462 1 ; Prompt for filetype 009462 1 20 8C 96 jsr DispString 009465 1 54 59 50 45 .byte "TYPE (BIN): $",0 009469 1 20 28 42 49 00946D 1 4E 29 3A 20 009471 1 24 00 009473 1 A9 06 lda #kFiletypeBinary 009475 1 85 06 sta Filetype 009477 1 20 2F 96 jsr InputNumberAX 00947A 1 F0 04 beq @defaultFiletype 00947C 1 B0 1D bcs @error 00947E 1 86 06 stx Filetype 009480 1 @defaultFiletype: 009480 1 009480 1 20 8C 96 jsr DispString 009483 1 20 20 20 20 .byte " NAME: ",0 009487 1 20 20 4E 41 00948B 1 4D 45 3A 20 00948F 1 00 009490 1 20 5C 98 jsr GetFilename 009493 1 F0 06 beq @empty 009495 1 009495 1 20 43 A2 jsr WriteFile 009498 1 20 18 97 jsr DisplayError 00949B 1 00949B 1 @empty: 00949B 1 @error: 00949B 1 60 rts 00949C 1 00949C 1 ;------------------------------------------------------------------------------ 00949C 1 ; MenuNewDirectory 00949C 1 ; 00949C 1 MenuNewDirectory: 00949C 1 20 8C 96 jsr DispString 00949F 1 4E 45 57 20 .byte "NEW DIRECTORY: ",0 0094A3 1 44 49 52 45 0094A7 1 43 54 4F 52 0094AB 1 59 3A 20 00 0094AF 1 20 5C 98 jsr GetFilename 0094B2 1 F0 06 beq @empty 0094B4 1 0094B4 1 20 D2 A3 jsr NewDirectoryAtRoot 0094B7 1 20 18 97 jsr DisplayError 0094BA 1 @empty: 0094BA 1 60 rts 0094BB 1 0094BB 1 ;------------------------------------------------------------------------------ 0094BB 1 ; MenuPrefix 0094BB 1 ; 0094BB 1 MenuPrefix: 0094BB 1 20 8C 96 jsr DispString 0094BE 1 50 52 45 46 .byte "PREFIX DIR: ",0 0094C2 1 49 58 20 44 0094C6 1 49 52 3A 20 0094CA 1 00 0094CB 1 20 5C 98 jsr GetFilename 0094CE 1 20 81 A4 jsr SetPrefix 0094D1 1 20 18 97 jsr DisplayError 0094D4 1 60 rts 0094D5 1 0094D5 1 ;------------------------------------------------------------------------------ 0094D5 1 ; MenuDeleteFile 0094D5 1 ; 0094D5 1 MenuDeleteFile: 0094D5 1 20 8C 96 jsr DispString 0094D8 1 44 45 4C 45 .byte "DELETE: ",0 0094DC 1 54 45 3A 20 0094E0 1 00 0094E1 1 20 5C 98 jsr GetFilename 0094E4 1 F0 06 beq @empty 0094E6 1 0094E6 1 20 95 A0 jsr Delete 0094E9 1 20 18 97 jsr DisplayError 0094EC 1 @empty: 0094EC 1 60 rts 0094ED 1 0094ED 1 0094ED 1 ;------------------------------------------------------------------------------ 0094ED 1 ; MenuRenameFile 0094ED 1 ; 0094ED 1 MenuRenameFile: 0094ED 1 20 8C 96 jsr DispString 0094F0 1 52 45 4E 41 .byte "RENAME: ",0 0094F4 1 4D 45 3A 20 0094F8 1 00 0094F9 1 20 5C 98 jsr GetFilename 0094FC 1 F0 2A beq @empty 0094FE 1 0094FE 1 A2 0F ldx #15 009500 1 @copyOrigName: 009500 1 BD 00 02 lda InputBuffer,x 009503 1 9D 80 02 sta InputBuffer2,x 009506 1 CA dex 009507 1 10 F7 bpl @copyOrigName 009509 1 009509 1 20 8C 96 jsr DispString 00950C 1 20 20 20 20 .byte " TO: ",0 009510 1 54 4F 3A 20 009514 1 00 009515 1 20 5C 98 jsr GetFilename 009518 1 F0 0E beq @empty 00951A 1 00951A 1 ; rename from InputBuffer2 to InputBuffer 00951A 1 A9 02 lda #>InputBuffer2 00951C 1 A2 80 ldx # 255 009825 1 .error "ERROR MESSAGE TABLE TOO LARGE" 009825 1 .endif 009825 1 009825 1 ;------------------------------------------------------------------------------ 009825 1 ; DispByte - Sends a Hex byte to the console 009825 1 ; Input: 009825 1 ; A = Hex number to display 009825 1 ; Ouput: 009825 1 ; None 009825 1 ; 009825 1 ; CPU Registers changed: A, P 009825 1 ; 009825 1 DispByteWithDollarSign: 009825 1 20 8C 96 jsr DispString 009828 1 24 00 .byte "$",0 00982A 1 DispByte: 00982A 1 48 pha 00982B 1 4A lsr a 00982C 1 4A lsr a 00982D 1 4A lsr a 00982E 1 4A lsr a 00982F 1 20 33 98 jsr Nibble 009832 1 68 pla 009833 1 Nibble: 009833 1 29 0F and #$0F 009835 1 09 30 ora #'0' 009837 1 C9 3A cmp #'0'+10 009839 1 90 02 bcc @digit 00983B 1 69 06 adc #6 00983D 1 @digit: 00983D 1 D0 0B bne DispChar ; always taken 00983F 1 00983F 1 ;------------------------------------------------------------------------------ 00983F 1 ; DispCR, DispSpace, and DispChar - Sends a char to the Apple1 console 00983F 1 ; 00983F 1 ; Input: 00983F 1 ; A = Character to Send 00983F 1 ; Ouput: 00983F 1 ; 00983F 1 ; ZeroPage Usage: 00983F 1 ; None 00983F 1 ; 00983F 1 ; CPU Registers changed: Acc, P 00983F 1 ; 00983F 1 ; X and Y are preserved. 00983F 1 ; 00983F 1 DispSpace: 00983F 1 A9 A0 lda #SPACE 009841 1 D0 07 bne DispChar 009843 1 PressSpaceAndDispCR: 009843 1 B0 03 bcs DispCR ; already hit ESC to abort 009845 1 20 6E 9A jsr PressSpaceOrESC 009848 1 DispCR: 009848 1 A9 8D lda #CR 00984A 1 DispChar: 00984A 1 .if APPLE2 00984A 1 ora #$80 00984A 1 stx xsave 00984A 1 sty ysave 00984A 1 jsr $fded 00984A 1 ldx xsave 00984A 1 ldy ysave 00984A 1 rts 00984A 1 xsave: 00984A 1 .byte 0 00984A 1 ysave: 00984A 1 .byte 0 00984A 1 .else 00984A 1 ; Wait until display is ready 00984A 1 2C 12 D0 bit DSP_DATA 00984D 1 30 FB bmi DispChar 00984F 1 ; Send character to display hardware 00984F 1 8D 12 D0 sta DSP_DATA 009852 1 60 rts 009853 1 .endif 009853 1 009853 1 ;------------------------------------------------------------------------------ 009853 1 ; WaitForKey - Wait until a key is pressed. Returns key stroke in Acc 009853 1 ; Input: 009853 1 ; None 009853 1 ; Ouput: 009853 1 ; Acc = ASCII value of key pressed 009853 1 ; 009853 1 ; X and Y are preserved. 009853 1 ; 009853 1 WaitForKey: 009853 1 .if APPLE2 009853 1 stx wfk_xsave 009853 1 sty wfk_ysave 009853 1 jsr $fd0c 009853 1 ldx wfk_xsave 009853 1 ldy wfk_ysave 009853 1 rts 009853 1 wfk_xsave: 009853 1 .byte 0 009853 1 wfk_ysave: 009853 1 .byte 0 009853 1 .else 009853 1 AD 11 D0 lda KEY_CONTROL 009856 1 10 FB bpl WaitForKey 009858 1 AD 10 D0 lda KEY_DATA 00985B 1 60 rts 00985C 1 .endif 00985C 1 00985C 1 ;------------------------------------------------------------------------------ 00985C 1 ; GetFilename 00985C 1 ; 00985C 1 ; Result: Sets Filename = InputBuffer and calls GETLN. 00985C 1 ; BEQ for an empty input 00985C 1 ; 00985C 1 GetFilename: 00985C 1 A9 02 lda #>InputBuffer 00985E 1 A2 00 ldx #PrefixDirectory 009AAA 1 A0 B0 ldy #kRootDirectoryBlock 009AF6 1 A2 02 ldx #DirectoryBuffer 009B94 1 A2 04 ldx #StagingBuffer 00A354 1 20 58 9D jsr ReadFileWithSpecialFirstBlock 00A357 1 B0 1E bcs @exit 00A359 1 00A359 1 A0 10 ldy #oFiletype 00A35B 1 B1 0B lda (EntryPtr),y 00A35D 1 C9 F1 cmp #kFiletypeBASIC1 00A35F 1 D0 13 bne @unknownFormat 00A361 1 00A361 1 AD 00 88 lda StagingBuffer 00A364 1 C9 41 cmp #'A' 00A366 1 D0 0C bne @unknownFormat 00A368 1 AD 01 88 lda StagingBuffer+1 00A36B 1 C9 31 cmp #'1' 00A36D 1 D0 05 bne @unknownFormat 00A36F 1 AD 02 88 lda StagingBuffer+2 ; version, must be 0 00A372 1 F0 04 beq @ok 00A374 1 @unknownFormat: 00A374 1 A9 FE lda #eUnknownBASICFormat 00A376 1 38 sec 00A377 1 @exit: 00A377 1 60 rts 00A378 1 @ok: 00A378 1 00A378 1 A2 4A ldx #$4A 00A37A 1 @copyZP: 00A37A 1 BD 00 88 lda StagingBuffer,x 00A37D 1 .if APPLE2 00A37D 1 sta $800,x 00A37D 1 .else 00A37D 1 95 00 sta 0,x 00A37F 1 .endif 00A37F 1 E8 inx 00A380 1 D0 F8 bne @copyZP 00A382 1 00A382 1 A9 00 lda #0 00A384 1 18 clc 00A385 1 60 rts 00A386 1 00A386 1 ;------------------------------------------------------------------------------ 00A386 1 ; SaveBASICFile 00A386 1 ; 00A386 1 ; Input: Filename 00A386 1 ; 00A386 1 ; We need to save zero page from $4A..FF, and all the memory between LOMEM 00A386 1 ; and HIMEM. We'll call WriteFile with a special request that it write from 00A386 1 ; StagingBuffer as the first block. The FileSize and Destination address we 00A386 1 ; request allow for the extra data in StagingBuffer. 00A386 1 ; 00A386 1 API_SaveBASICFile: 00A386 1 SaveBASICFile: 00A386 1 A9 00 lda #0 00A388 1 AA tax 00A389 1 @zero: 00A389 1 9D 00 88 sta StagingBuffer,x 00A38C 1 9D 00 89 sta StagingBuffer+256,x 00A38F 1 CA dex 00A390 1 D0 F7 bne @zero 00A392 1 00A392 1 A9 41 lda #'A' 00A394 1 8D 00 88 sta StagingBuffer 00A397 1 A9 31 lda #'1' 00A399 1 8D 01 88 sta StagingBuffer+1 00A39C 1 ; StagingBuffer+2 is the file format version. Leave it as 0 for now. 00A39C 1 00A39C 1 A2 4A ldx #$4A 00A39E 1 @copyZP: 00A39E 1 B5 00 lda 0,x 00A3A0 1 9D 00 88 sta StagingBuffer,x 00A3A3 1 E8 inx 00A3A4 1 D0 F8 bne @copyZP 00A3A6 1 00A3A6 1 A6 4B ldx LOMEM+1 00A3A8 1 A4 4A ldy LOMEM 00A3AA 1 86 08 stx Auxtype+1 00A3AC 1 84 07 sty Auxtype 00A3AE 1 CA dex 00A3AF 1 CA dex ; subtract 2 to allow for extra buffer 00A3B0 1 86 01 stx Destination+1 00A3B2 1 84 00 sty Destination 00A3B4 1 00A3B4 1 38 sec 00A3B5 1 A5 4C lda HIMEM 00A3B7 1 E5 4A sbc LOMEM 00A3B9 1 85 09 sta FileSize 00A3BB 1 A5 4D lda HIMEM+1 00A3BD 1 E5 4B sbc LOMEM+1 00A3BF 1 90 0D bcc @error 00A3C1 1 69 01 adc #1 ; adds 2, since carry is set 00A3C3 1 85 0A sta FileSize+1 00A3C5 1 00A3C5 1 A9 F1 lda #kFiletypeBASIC1 00A3C7 1 85 06 sta Filetype 00A3C9 1 A9 88 lda #>StagingBuffer 00A3CB 1 4C 45 A2 jmp WriteFileWithSpecialFirstBlock 00A3CE 1 00A3CE 1 @error: 00A3CE 1 A9 56 lda #eBadBufferAddr 00A3D0 1 38 sec 00A3D1 1 60 rts 00A3D2 1 00A3D2 1 00A3D2 1 ;------------------------------------------------------------------------------ 00A3D2 1 ; NewDirectoryAtRoot 00A3D2 1 ; 00A3D2 1 ; Input: Filename = name of directory 00A3D2 1 ; Output: CLC for success, SEC/A=error 00A3D2 1 ; 00A3D2 1 API_NewDirectoryAtRoot: 00A3D2 1 NewDirectoryAtRoot: 00A3D2 1 20 B0 9B jsr DoNotUsePrefix 00A3D5 1 20 F3 A5 jsr LocateDirEntryForFilename 00A3D8 1 20 B7 9B jsr UsePrefixNormally 00A3DB 1 90 06 bcc @dup 00A3DD 1 C9 46 cmp #eFileNotFound 00A3DF 1 F0 06 beq @continue 00A3E1 1 38 sec 00A3E2 1 60 rts 00A3E3 1 @dup: 00A3E3 1 A9 47 lda #eDuplicateFile 00A3E5 1 38 sec 00A3E6 1 @exit: 00A3E6 1 60 rts 00A3E7 1 00A3E7 1 @continue: 00A3E7 1 20 B0 9B jsr DoNotUsePrefix 00A3EA 1 20 18 A6 jsr LocateAvailableDirEntry 00A3ED 1 20 B7 9B jsr UsePrefixNormally 00A3F0 1 B0 F4 bcs @exit 00A3F2 1 00A3F2 1 ; zero out the new directory entry 00A3F2 1 A0 26 ldy #kDirEntrySize-1 00A3F4 1 A9 00 lda #0 00A3F6 1 @zero: 00A3F6 1 91 0B sta (EntryPtr),y 00A3F8 1 88 dey 00A3F9 1 10 FB bpl @zero 00A3FB 1 00A3FB 1 ; construct the dir entry (EntryPtr) in parallel with the directory header (Buffer) 00A3FB 1 20 D0 A5 jsr ZeroBuffer 00A3FE 1 00A3FE 1 ; allocate the new dir's key block & store it into the directory entry 00A3FE 1 20 27 9C jsr ReadFirstBitmapBlock 00A401 1 B0 E3 bcs @exit 00A403 1 20 5D 9C jsr AllocateOneBlockAX ;also sets pdBlockNumber 00A406 1 @exit1: 00A406 1 B0 DE bcs @exit 00A408 1 00A408 1 A0 12 ldy #oKeyBlock+1 00A40A 1 91 0B sta (EntryPtr),y 00A40C 1 8A txa 00A40D 1 88 dey 00A40E 1 91 0B sta (EntryPtr),y 00A410 1 00A410 1 ; set the name 00A410 1 A0 00 ldy #0 00A412 1 B1 02 lda (Filename),y 00A414 1 A8 tay 00A415 1 @copyName: 00A415 1 B1 02 lda (Filename),y 00A417 1 91 0B sta (EntryPtr),y 00A419 1 99 04 8A sta buffer+oVolStorageType,y 00A41C 1 88 dey 00A41D 1 10 F6 bpl @copyName 00A41F 1 00A41F 1 ; set the storage type to Directory 00A41F 1 A9 D0 lda #kDirectory 00A421 1 A0 00 ldy #0 00A423 1 11 0B ora (EntryPtr),y 00A425 1 91 0B sta (EntryPtr),y 00A427 1 ; set the dir header's storage type 00A427 1 A9 E0 lda #kSubdirHeader 00A429 1 0D 04 8A ora buffer+oVolStorageType 00A42C 1 8D 04 8A sta buffer+oVolStorageType 00A42F 1 00A42F 1 ; set the filetype 00A42F 1 A0 10 ldy #oFiletype 00A431 1 A9 0F lda #kFiletypeDirectory 00A433 1 91 0B sta (EntryPtr),y 00A435 1 00A435 1 ; set the block count to 1 00A435 1 A0 13 ldy #oBlockCount 00A437 1 A9 01 lda #1 00A439 1 91 0B sta (EntryPtr),y 00A43B 1 00A43B 1 ; set the access to Unlocked 00A43B 1 A0 1E ldy #oAccess 00A43D 1 A9 E3 lda #kAccessFull+kAccessNeedsBackup 00A43F 1 91 0B sta (EntryPtr),y 00A441 1 8D 22 8A sta buffer+oVolAccess 00A444 1 00A444 1 ; set the end of file (3 bytes) to $0200 00A444 1 A0 16 ldy #oFileSize+1 00A446 1 A9 02 lda #$02 00A448 1 91 0B sta (EntryPtr),y 00A44A 1 00A44A 1 ; set the Header Pointer field to the first block of the (root) directory 00A44A 1 A0 25 ldy #oHeaderPointer 00A44C 1 AD AD 87 lda FirstDirectoryBlock 00A44F 1 91 0B sta (EntryPtr),y 00A451 1 C8 iny 00A452 1 AD AE 87 lda FirstDirectoryBlock+1 00A455 1 91 0B sta (EntryPtr),y 00A457 1 00A457 1 ; set entry_length, parent_entry_length 00A457 1 A9 27 lda #kDirEntrySize 00A459 1 8D 23 8A sta buffer+oVolEntryLength 00A45C 1 8D 2A 8A sta buffer+oSubdirParentEntryLength 00A45F 1 ; set entries per block 00A45F 1 A9 0D lda #kEntriesPerBlock 00A461 1 8D 24 8A sta buffer+oVolEntriesPerBlock 00A464 1 00A464 1 ; parent_pointer (block #), parent_entry_number (subdir header knows where its directory entry is) 00A464 1 A5 0E lda DirectoryBlock+1 00A466 1 A6 0D ldx DirectoryBlock 00A468 1 8D 28 8A sta buffer+oSubdirParentPointer+1 00A46B 1 8E 27 8A stx buffer+oSubdirParentPointer 00A46E 1 00A46E 1 ; compute parent entry number = entries-per-block + 1 - EntryCounter 00A46E 1 38 sec 00A46F 1 A9 0E lda #kEntriesPerBlock+1 00A471 1 E5 19 sbc EntryCounter 00A473 1 8D 29 8A sta buffer+oSubdirParentEntryNum 00A476 1 00A476 1 ; finish up by writing the directory's first block and the directory entry 00A476 1 20 19 A7 jsr UseBuffer 00A479 1 20 63 A7 jsr DoWriteBlock 00A47C 1 B0 88 bcs @exit1 00A47E 1 00A47E 1 4C 35 A3 jmp FlushBitmapAndIncrementFileCount 00A481 1 00A481 1 00A481 1 ;------------------------------------------------------------------------------ 00A481 1 ; SetPrefix 00A481 1 ; 00A481 1 ; Input: Filename = name of directory (empty = use root) 00A481 1 ; 00A481 1 SetPrefix: 00A481 1 A0 00 ldy #0 00A483 1 B1 02 lda (Filename),y 00A485 1 F0 10 beq @emptyPrefix 00A487 1 00A487 1 20 B0 9B jsr DoNotUsePrefix 00A48A 1 20 F3 A5 jsr LocateDirEntryForFilename 00A48D 1 20 B7 9B jsr UsePrefixNormally 00A490 1 B0 12 bcs @error 00A492 1 20 D9 9A jsr RequireDirectory 00A495 1 B0 0D bcs @error 00A497 1 00A497 1 @emptyPrefix: 00A497 1 A0 0F ldy #15 00A499 1 @copyPrefix: 00A499 1 B1 02 lda (Filename),y 00A49B 1 99 B0 87 sta PrefixDirectory,y 00A49E 1 88 dey 00A49F 1 10 F8 bpl @copyPrefix 00A4A1 1 00A4A1 1 A9 00 lda #0 00A4A3 1 38 sec 00A4A4 1 @error: 00A4A4 1 60 rts 00A4A5 1 00A4A5 1 00A4A5 1 ;------------------------------------------------------------------------------ 00A4A5 1 ; FormatDrive 00A4A5 1 ; 00A4A5 1 ; Input: Filename = volume name 00A4A5 1 ; DriveNumber 00A4A5 1 ; 00A4A5 1 FormatDrive: 00A4A5 1 20 C7 A6 jsr SyntaxCheckFilename 00A4A8 1 B0 13 bcs @exit 00A4AA 1 00A4AA 1 ; GetStatus for the block count. 00A4AA 1 A9 00 lda #PRODOS_STATUS 00A4AC 1 85 42 sta pdCommandCode 00A4AE 1 20 98 A7 jsr CFBlockDriver 00A4B1 1 B0 0A bcs @exit 00A4B3 1 84 14 sty TotalBlocks+1 00A4B5 1 86 13 stx TotalBlocks 00A4B7 1 98 tya 00A4B8 1 D0 04 bne @enoughBlocks 00A4BA 1 A9 2D lda #PRODOS_BADBLOCK 00A4BC 1 38 sec 00A4BD 1 @exit: 00A4BD 1 60 rts 00A4BE 1 @enoughBlocks: 00A4BE 1 00A4BE 1 ; Zero out blocks 0 through 64 00A4BE 1 20 D0 A5 jsr ZeroBuffer 00A4C1 1 20 19 A7 jsr UseBuffer 00A4C4 1 A9 00 lda #0 00A4C6 1 A2 40 ldx #64 00A4C8 1 85 47 sta pdBlockNumberHigh 00A4CA 1 86 46 stx pdBlockNumberLow 00A4CC 1 @zeroBlocks: 00A4CC 1 20 63 A7 jsr DoWriteBlock 00A4CF 1 B0 EC bcs @exit 00A4D1 1 C6 46 dec pdBlockNumberLow 00A4D3 1 10 F7 bpl @zeroBlocks 00A4D5 1 00A4D5 1 ; Construct and write block 2, the main directory block. 00A4D5 1 A0 00 ldy #0 00A4D7 1 B1 02 lda (Filename),y 00A4D9 1 A8 tay 00A4DA 1 @copyName: 00A4DA 1 B1 02 lda (Filename),y 00A4DC 1 99 04 8A sta buffer+oVolStorageType,y 00A4DF 1 88 dey 00A4E0 1 10 F8 bpl @copyName 00A4E2 1 09 F0 ora #kVolume 00A4E4 1 8D 04 8A sta buffer+oVolStorageType 00A4E7 1 00A4E7 1 A9 03 lda #kRootDirectoryBlock+1 00A4E9 1 8D 02 8A sta buffer+oDirLinkNext 00A4EC 1 A9 05 lda #5 00A4EE 1 8D 20 8A sta buffer+oVolVersion 00A4F1 1 A9 E3 lda #kAccessFull+kAccessNeedsBackup 00A4F3 1 8D 22 8A sta buffer+oVolAccess 00A4F6 1 A9 27 lda #kDirEntrySize 00A4F8 1 8D 23 8A sta buffer+oVolEntryLength 00A4FB 1 A9 0D lda #kEntriesPerBlock 00A4FD 1 8D 24 8A sta buffer+oVolEntriesPerBlock 00A500 1 A9 06 lda #kCanonicalFirstBitmapBlock 00A502 1 8D 27 8A sta buffer+oVolBitmapNumber 00A505 1 85 0F sta BitmapBase 00A507 1 A5 14 lda TotalBlocks+1 00A509 1 A6 13 ldx TotalBlocks 00A50B 1 8D 2A 8A sta buffer+oVolTotalBlocks+1 00A50E 1 8E 29 8A stx buffer+oVolTotalBlocks 00A511 1 00A511 1 00A511 1 A9 00 lda #>kRootDirectoryBlock 00A513 1 A2 02 ldx # 1 00A713 1 E8 inx ; 1 more for the index block 00A714 1 8A txa 00A715 1 60 rts 00A716 1 00A716 1 @needsJustOneBlock: 00A716 1 A9 01 lda #1 00A718 1 60 rts 00A719 1 00A719 1 00A719 1 ;------------------------------------------------------------------------------ 00A719 1 UseBuffer: 00A719 1 A0 8A ldy #>buffer 00A71B 1 D0 06 bne ioBufferY 00A71D 1 ;------------------------------------------------------------------------------ 00A71D 1 UseDirectoryBuffer: 00A71D 1 A0 8C ldy #>DirectoryBuffer 00A71F 1 D0 02 bne ioBufferY 00A721 1 ;------------------------------------------------------------------------------ 00A721 1 ; Sets pdIOBuffer. Preserves A,X and returns with Y=0. 00A721 1 ; 00A721 1 UseBitmapBuffer: 00A721 1 A0 8E ldy #>BitmapBuffer 00A723 1 ioBufferY: 00A723 1 84 45 sty pdIOBufferHigh 00A725 1 A0 00 ldy #0 00A727 1 84 44 sty pdIOBufferLow 00A729 1 60 rts 00A72A 1 00A72A 1 ;------------------------------------------------------------------------------ 00A72A 1 UseDestinationOrSpecialBuffer: 00A72A 1 AC 02 87 ldy SpecialFirstBlock 00A72D 1 F0 07 beq UseDestination 00A72F 1 20 23 A7 jsr ioBufferY 00A732 1 8C 02 87 sty SpecialFirstBlock 00A735 1 60 rts 00A736 1 UseDestination: 00A736 1 A4 01 ldy Destination+1 00A738 1 84 45 sty pdIOBufferHigh 00A73A 1 A4 00 ldy Destination 00A73C 1 84 44 sty pdIOBufferLow 00A73E 1 60 rts 00A73F 1 00A73F 1 ;------------------------------------------------------------------------------ 00A73F 1 ; ReadBlockAXOrZeroes 00A73F 1 ; 00A73F 1 ; Read any block except #0. If asked to read block 0, fill the buffer with 00A73F 1 ; 512 bytes of $00 instead. This facilitates reading a sparse file, where 00A73F 1 ; the index block entry for a missing portion of a file is 0. 00A73F 1 ; 00A73F 1 ReadBlockAXOrZeroes: 00A73F 1 85 47 sta pdBlockNumberHigh 00A741 1 86 46 stx pdBlockNumberLow 00A743 1 05 46 ora pdBlockNumberLow 00A745 1 D0 4D bne DoReadBlock 00A747 1 A8 tay 00A748 1 @zero1: 00A748 1 91 44 sta (pdIOBufferLow),y 00A74A 1 C8 iny 00A74B 1 D0 FB bne @zero1 00A74D 1 E6 45 inc pdIOBufferHigh 00A74F 1 @zero2: 00A74F 1 91 44 sta (pdIOBufferLow),y 00A751 1 C8 iny 00A752 1 D0 FB bne @zero2 00A754 1 C6 45 dec pdIOBufferHigh 00A756 1 18 clc 00A757 1 60 rts 00A758 1 00A758 1 ;------------------------------------------------------------------------------ 00A758 1 WriteCurrentDirectoryBlock: 00A758 1 20 1D A7 jsr UseDirectoryBuffer 00A75B 1 A5 0E lda DirectoryBlock+1 00A75D 1 A6 0D ldx DirectoryBlock 00A75F 1 WriteBlockAX: 00A75F 1 85 47 sta pdBlockNumberHigh 00A761 1 86 46 stx pdBlockNumberLow 00A763 1 DoWriteBlock: 00A763 1 A9 02 lda #PRODOS_WRITE 00A765 1 85 42 sta pdCommandCode 00A767 1 D0 2F bne CFBlockDriver 00A769 1 00A769 1 ;------------------------------------------------------------------------------ 00A769 1 ; FlushAndReadFirstDirectoryBlock, FlushAndReadDirectoryBlockAX 00A769 1 ; 00A769 1 ; Read a directory block into DirectoryBuffer, writing out the current block 00A769 1 ; first. 00A769 1 ; 00A769 1 ; Result: CLC for success 00A769 1 ; SEC, A = error 00A769 1 ; 00A769 1 FlushAndReadFirstDirectoryBlock: 00A769 1 AD AE 87 lda FirstDirectoryBlock+1 00A76C 1 AE AD 87 ldx FirstDirectoryBlock 00A76F 1 FlushAndReadDirectoryBlockAX: 00A76F 1 C5 0E cmp DirectoryBlock+1 00A771 1 D0 06 bne @different 00A773 1 E4 0D cpx DirectoryBlock 00A775 1 D0 02 bne @different 00A777 1 18 clc 00A778 1 60 rts 00A779 1 @different: 00A779 1 48 pha 00A77A 1 8A txa 00A77B 1 48 pha 00A77C 1 20 58 A7 jsr WriteCurrentDirectoryBlock 00A77F 1 90 05 bcc @noError 00A781 1 AA tax 00A782 1 68 pla 00A783 1 68 pla 00A784 1 8A txa 00A785 1 60 rts 00A786 1 @noError: 00A786 1 68 pla 00A787 1 AA tax 00A788 1 68 pla 00A789 1 ReadDirectoryBlockAX: 00A789 1 20 1D A7 jsr UseDirectoryBuffer 00A78C 1 85 0E sta DirectoryBlock+1 00A78E 1 86 0D stx DirectoryBlock 00A790 1 ReadBlockAX: 00A790 1 85 47 sta pdBlockNumberHigh 00A792 1 86 46 stx pdBlockNumberLow 00A794 1 DoReadBlock: 00A794 1 A9 01 lda #PRODOS_READ 00A796 1 85 42 sta pdCommandCode 00A798 1 ; Fall into CF block driver below. If Block driver moves, place "jmp CFBlockDriver" here 00A798 1 ;------------------------------------------------------------------------------ 00A798 1 ; Low Level CF Driver Entry point 00A798 1 ; 00A798 1 ; unit number not used currently 00A798 1 CFBlockDriver: 00A798 1 2C 01 87 bit CFFA1_Options 00A79B 1 10 09 bpl CFBlockDriverInternal 00A79D 1 20 64 A9 jsr LogBlockOperationBefore 00A7A0 1 20 A6 A7 jsr CFBlockDriverInternal 00A7A3 1 4C BC A9 jmp LogBlockOperationAfter 00A7A6 1 00A7A6 1 CFBlockDriverInternal: 00A7A6 1 .if APPLE2 00A7A6 1 jmp ReadOrWriteBlockAppleII 00A7A6 1 .else 00A7A6 1 ; 00A7A6 1 ; Set CF card into 8bit mode 00A7A6 1 ; 00A7A6 1 A9 01 lda #Enable8BitTransfers 00A7A8 1 8D F9 AF sta ATAFeature 00A7AB 1 A9 00 lda #$00 ; Drive=0 00A7AD 1 8D FE AF sta ATA_LBA27_24 ; Talk to the Master device and use LBA mode. 00A7B0 1 A9 EF lda #ATASetFeature 00A7B2 1 8D FF AF sta ATACommand ;Issue the 8-bit feature command to the drive 00A7B5 1 00A7B5 1 ; Don't wait here for CF card to be ready. Ready is check below already. 00A7B5 1 ;;;; jsr IDEWaitReady ;Wait for BUSY flag to clear 00A7B5 1 00A7B5 1 00A7B5 1 ; process the command code and jump to appropriate routine. 00A7B5 1 00A7B5 1 A5 42 lda pdCommandCode 00A7B7 1 C9 01 cmp #PRODOS_READ 00A7B9 1 F0 0F beq ReadBlock 00A7BB 1 00A7BB 1 C9 02 cmp #PRODOS_WRITE 00A7BD 1 F0 63 beq WriteBlock 00A7BF 1 00A7BF 1 C9 00 cmp #PRODOS_STATUS 00A7C1 1 D0 03 bne @notStatus 00A7C3 1 4C 9A A8 jmp GetStatus 00A7C6 1 @notStatus: 00A7C6 1 00A7C6 1 A9 27 lda #PRODOS_IO_ERROR 00A7C8 1 38 sec 00A7C9 1 60 rts 00A7CA 1 00A7CA 1 ;------------------------------------------------------------------------------ 00A7CA 1 ; ReadBlock - Read a block from device into memory 00A7CA 1 ; 00A7CA 1 ; Input: 00A7CA 1 ; pd Command Block Data $42 - $47 00A7CA 1 ; 00A7CA 1 ; Output: 00A7CA 1 ; A = ProDOS read return code 00A7CA 1 ; Carry flag: 0 = Okay, 1 = Error 00A7CA 1 ; 00A7CA 1 ; ZeroPage Usage: 00A7CA 1 ; $F0 00A7CA 1 ; Note: location $F0 is saved and restored before driver exits 00A7CA 1 ; 00A7CA 1 ReadBlock: 00A7CA 1 00A7CA 1 A5 45 lda pdIOBufferHigh 00A7CC 1 48 pha 00A7CD 1 A5 F0 lda zpt1 00A7CF 1 48 pha 00A7D0 1 00A7D0 1 20 DC A7 jsr ReadBlockCore 00A7D3 1 AA tax ; ver1.3: Save Acc 00A7D4 1 00A7D4 1 68 pla 00A7D5 1 85 F0 sta zpt1 00A7D7 1 68 pla 00A7D8 1 85 45 sta pdIOBufferHigh 00A7DA 1 8A txa ; ver1.3: restore Acc 00A7DB 1 60 rts 00A7DC 1 00A7DC 1 ReadBlockCore: 00A7DC 1 00A7DC 1 20 28 A9 jsr IDEWaitReady 00A7DF 1 20 80 A8 jsr SetupTaskFile ;Program the device's task file registers 00A7E2 1 ; based on ProDOS address 00A7E2 1 00A7E2 1 A9 20 lda #ATACRead 00A7E4 1 8D FF AF sta ATACommand ;Issue the read command to the drive 00A7E7 1 20 28 A9 jsr IDEWaitReady ;Wait for BUSY flag to clear 00A7EA 1 00A7EA 1 AD FF AF lda ATAStatus ;Check for error response from device 00A7ED 1 29 09 and #$09 00A7EF 1 C9 01 cmp #$01 ;If DRQ=0 and ERR=1 a device error occured 00A7F1 1 D0 04 bne rCommandOK 00A7F3 1 00A7F3 1 ; 00A7F3 1 ; The drive has returned an error code. Just return I/O error code to PRODOS 00A7F3 1 ; 00A7F3 1 A9 27 lda #PRODOS_IO_ERROR 00A7F5 1 38 sec 00A7F6 1 60 rts 00A7F7 1 ; 00A7F7 1 ; Sector is ready to read 00A7F7 1 ; 00A7F7 1 rCommandOK: 00A7F7 1 A0 02 ldy #2 00A7F9 1 84 F0 sty zpt1 00A7FB 1 A0 00 ldy #0 00A7FD 1 00A7FD 1 rLoop: 00A7FD 1 AD FF AF lda ATAStatus ;Note: not using IDEWaitReady, using inline code 00A800 1 30 FB bmi rLoop ;Wait for BUSY (bit 7) to be zero 00A802 1 29 08 and #$08 ;get DRQ status bit 00A804 1 F0 18 beq rShort ;if off, didn't get enough data 00A806 1 00A806 1 AD F8 AF lda ATAData 00A809 1 91 44 sta (pdIOBufferLow),y 00A80B 1 C8 iny 00A80C 1 00A80C 1 AD F8 AF lda ATAData 00A80F 1 91 44 sta (pdIOBufferLow),y 00A811 1 C8 iny 00A812 1 00A812 1 D0 E9 bne rLoop 00A814 1 E6 45 inc pdIOBufferHigh 00A816 1 C6 F0 dec zpt1 00A818 1 D0 E3 bne rLoop 00A81A 1 00A81A 1 A9 00 lda #0 00A81C 1 18 clc 00A81D 1 60 rts 00A81E 1 ; 00A81E 1 ; The Block was short, return I/O error code to ProDOS 00A81E 1 ; 00A81E 1 rShort: 00A81E 1 A9 27 lda #PRODOS_IO_ERROR 00A820 1 38 sec 00A821 1 60 rts 00A822 1 00A822 1 ;------------------------------------------------------------------------ 00A822 1 ; WriteBlock - Write a block in memory to device 00A822 1 ; 00A822 1 ; Input: 00A822 1 ; pd Command Block Data $42 - $47 00A822 1 ; X = requested slot number in form $n0 where n = slot 1 to 7 00A822 1 ; 00A822 1 ; Output: 00A822 1 ; A = ProDOS write return code 00A822 1 ; Carry flag: 0 = Okay, 1 = Error 00A822 1 ; 00A822 1 WriteBlock: 00A822 1 A5 45 lda pdIOBufferHigh 00A824 1 48 pha 00A825 1 A5 F0 lda zpt1 00A827 1 48 pha 00A828 1 00A828 1 20 34 A8 jsr WriteBlockCore 00A82B 1 AA tax 00A82C 1 00A82C 1 68 pla 00A82D 1 85 F0 sta zpt1 00A82F 1 68 pla 00A830 1 85 45 sta pdIOBufferHigh 00A832 1 8A txa 00A833 1 60 rts 00A834 1 00A834 1 WriteBlockCore: 00A834 1 20 28 A9 jsr IDEWaitReady 00A837 1 20 80 A8 jsr SetupTaskFile ;program IDE task file 00A83A 1 00A83A 1 ; Write sector from RAM 00A83A 1 A9 30 lda #ATACWrite 00A83C 1 8D FF AF sta ATACommand 00A83F 1 20 28 A9 jsr IDEWaitReady 00A842 1 00A842 1 AD FF AF lda ATAStatus ;Check for error response from writing command 00A845 1 29 09 and #$09 00A847 1 C9 01 cmp #$01 ;if DRQ=0 and ERR=1 an error occured 00A849 1 D0 04 bne wCommandOK 00A84B 1 00A84B 1 ; The drive has returned an error code. Just return I/O error code to PRODOS 00A84B 1 ; 00A84B 1 A9 27 lda #PRODOS_IO_ERROR 00A84D 1 38 sec 00A84E 1 60 rts 00A84F 1 ; 00A84F 1 ; Sector is ready to write 00A84F 1 ; 00A84F 1 wCommandOK: 00A84F 1 A0 02 ldy #2 00A851 1 84 F0 sty zpt1 00A853 1 A0 00 ldy #0 00A855 1 00A855 1 wLoop: 00A855 1 AD FF AF lda ATAStatus ;Note: not using IDEWaitReady, using inline code 00A858 1 30 FB bmi wLoop ;Wait for BUSY (bit 7) to be zero 00A85A 1 29 08 and #$08 ;get DRQ status bit 00A85C 1 F0 1E beq wShort ;if off, didn't get enough data 00A85E 1 00A85E 1 2C F1 AF bit SetCSMask ;Block all read cycles (esp the extra ones preceeding write cycles) 00A861 1 00A861 1 B1 44 lda (pdIOBufferLow),y 00A863 1 8D F8 AF sta ATAData 00A866 1 C8 iny 00A867 1 B1 44 lda (pdIOBufferLow),y 00A869 1 8D F8 AF sta ATAData 00A86C 1 00A86C 1 2C F2 AF bit ClearCSMask ;Set back to normal, allow CS0 assertions on read cycles 00A86F 1 00A86F 1 C8 iny 00A870 1 D0 E3 bne wLoop 00A872 1 E6 45 inc pdIOBufferHigh 00A874 1 C6 F0 dec zpt1 00A876 1 D0 DD bne wLoop 00A878 1 00A878 1 A9 00 lda #0 00A87A 1 18 clc 00A87B 1 60 rts 00A87C 1 ; 00A87C 1 ; The Block was short, return I/O error code to PRODOS 00A87C 1 ; 00A87C 1 wShort: 00A87C 1 A9 27 lda #PRODOS_IO_ERROR 00A87E 1 38 sec 00A87F 1 60 rts 00A880 1 00A880 1 ;------------------------------------------------------------------------------ 00A880 1 ; SetupTaskFile - Program CF registers with block address to be accessed 00A880 1 ; For now, no block number to LBA translation 00A880 1 ; 00A880 1 SetupTaskFile: 00A880 1 00A880 1 A5 46 lda pdBlockNumberLow 00A882 1 8D FB AF sta ATA_LBA07_00 ;store ProDOS Low block # into LBA 0-7 00A885 1 00A885 1 A5 47 lda pdBlockNumberHigh 00A887 1 8D FC AF sta ATA_LBA15_08 ;store ProDOS High block # into LBA 15-8 00A88A 1 00A88A 1 A9 00 lda #0 00A88C 1 8D FD AF sta ATA_LBA23_16 ;store LBA bits 23-16 00A88F 1 00A88F 1 A9 E0 lda #$E0 ; 1, (LBA), 1, (Drive), LBA 27-24, where LBA=1, Drive=0 00A891 1 8D FE AF sta ATA_LBA27_24 ; Talk to the Master device and use LBA mode. 00A894 1 00A894 1 A9 01 lda #1 00A896 1 8D FA AF sta ATASectorCnt 00A899 1 60 rts 00A89A 1 00A89A 1 ;------------------------------------------------------------------------------ 00A89A 1 ; GetStatus - Called by ProDOS and SmartPort to get device status and size 00A89A 1 ; 00A89A 1 ; Input: 00A89A 1 ; DriveNumber (0 to 3) 00A89A 1 ; 00A89A 1 ; Output: 00A89A 1 ; A = ProDOS status return code 00A89A 1 ; X = drive size LSB 00A89A 1 ; Y = drive size MSB 00A89A 1 ; Carry flag: 0 = Okay, 1 = Error 00A89A 1 ; DrvBlkCount0..DrvBlkCount2 = usable blocks on device 00A89A 1 ; 00A89A 1 GetStatus: 00A89A 1 ; 00A89A 1 ; Determine if a drive/device is present. 00A89A 1 ; 00A89A 1 20 32 A9 jsr CheckDevice 00A89D 1 B0 6F bcs NoDrive 00A89F 1 00A89F 1 ; Device is present 00A89F 1 sDriveOK: 00A89F 1 20 28 A9 jsr IDEWaitReady 00A8A2 1 A9 EC lda #ATAIdentify 00A8A4 1 8D FF AF sta ATACommand ;Issue the read command to the drive 00A8A7 1 20 28 A9 jsr IDEWaitReady ;Wait for BUSY flag to go away 00A8AA 1 00A8AA 1 AD FF AF lda ATAStatus ;Check for error response 00A8AD 1 29 09 and #$09 00A8AF 1 C9 01 cmp #$01 ;if DRQ=0 and ERR=1 an error occured 00A8B1 1 D0 04 bne sValidATACommand 00A8B3 1 00A8B3 1 A9 27 lda #PRODOS_IO_ERROR 00A8B5 1 D0 59 bne sError ; Command Error occured, return error 00A8B7 1 00A8B7 1 sValidATACommand: 00A8B7 1 A0 00 ldy #$00 ;zero loop counter 00A8B9 1 00A8B9 1 sPrefetchloop: 00A8B9 1 20 28 A9 jsr IDEWaitReady ;See if a word is ready 00A8BC 1 B0 04 bcs sWordRdy 00A8BE 1 A9 27 lda #PRODOS_IO_ERROR 00A8C0 1 D0 4E bne sError 00A8C2 1 00A8C2 1 sWordRdy: 00A8C2 1 AD F8 AF lda ATAData ;Read words 0 thru 56 but throw them away 00A8C5 1 C8 iny 00A8C6 1 C0 72 cpy #114 ;57 * 2 ;Number of the last byte you want to throw away 00A8C8 1 D0 EF bne sPrefetchloop 00A8CA 1 00A8CA 1 sPrefetchDone: 00A8CA 1 AD F8 AF lda ATAData ;Read the current capacity in sectors (LBA) 00A8CD 1 .if BLOCKOFFSET<>0 00A8CD 1 sec 00A8CD 1 sbc #BLOCKOFFSET 00A8CD 1 .endif 00A8CD 1 8D 05 87 sta DrvBlkCount0 00A8D0 1 AD F8 AF lda ATAData 00A8D3 1 .if BLOCKOFFSET<>0 00A8D3 1 sbc #0 00A8D3 1 .endif 00A8D3 1 8D 06 87 sta DrvBlkCount1 00A8D6 1 AD F8 AF lda ATAData 00A8D9 1 .if BLOCKOFFSET<>0 00A8D9 1 sbc #0 00A8D9 1 .endif 00A8D9 1 8D 07 87 sta DrvBlkCount2 00A8DC 1 00A8DC 1 00A8DC 1 AD 07 87 lda DrvBlkCount2 00A8DF 1 C9 04 cmp #PARTITIONS32MB ;max out at (#PARTITIONS32MB * $10000 + 00FFFF) 00A8E1 1 ; blocks 00A8E1 1 B0 05 bcs maxOutAtN 00A8E3 1 00A8E3 1 AD F8 AF lda ATAData 00A8E6 1 F0 0D beq lessThan8GB 00A8E8 1 maxOutAtN: 00A8E8 1 A9 FF lda #$FF ;The device is truly huge! Just set our 3-byte 00A8EA 1 ; block count to $03FFFF 00A8EA 1 8D 05 87 sta DrvBlkCount0 00A8ED 1 8D 06 87 sta DrvBlkCount1 00A8F0 1 A9 03 lda #PARTITIONS32MB-1 ;Number of 32MB devices, set by the equate: 00A8F2 1 ; #PARTITIONS32MB 00A8F2 1 8D 07 87 sta DrvBlkCount2 00A8F5 1 lessThan8GB: 00A8F5 1 00A8F5 1 00A8F5 1 PostFetch: 00A8F5 1 20 28 A9 jsr IDEWaitReady ;read the rest of the words, until command ends 00A8F8 1 90 06 bcc sReadComplete 00A8FA 1 AD F8 AF lda ATAData 00A8FD 1 4C F5 A8 jmp PostFetch 00A900 1 sReadComplete: 00A900 1 00A900 1 ; DrvBlkCount2 is the number of 32 MB partitions availiable - 1, 00A900 1 ; or the highest drive # supported (zero based). 00A900 1 ; 00A900 1 ; If DrvBlkCount2 > drive # then StatusSize = $FFFF 00A900 1 ; If DrvBlkCount2 = drive # then StatusSize = DrvBlkCount1,DrvBlkCount0 00A900 1 ; If DrvBlkCount2 < drive # then StatusSize = 0 00A900 1 ; 00A900 1 ; This scheme has a special case which must be handled because ProDOS 00A900 1 ; partitions are not quite 32 meg in size but are only FFFF blocks in size. 00A900 1 ; If a device is exactly: 32meg or 10000h blocks in size, it would appear 00A900 1 ; as one drive of size FFFF and another drive of size 0000. To handle this 00A900 1 ; case, we check for an exact size of 0000 and fall into the NoDrive code. 00A900 1 ; 00A900 1 AD 03 87 lda DriveNumber 00A903 1 CD 07 87 cmp DrvBlkCount2 00A906 1 F0 0E beq ExactSize 00A908 1 A2 FF ldx #$FF 00A90A 1 A0 FF ldy #$FF 00A90C 1 90 16 bcc sNoError ; full size ($FFFF blocks) 00A90E 1 00A90E 1 NoDrive: 00A90E 1 A9 2F lda #PRODOS_OFFLINE 00A910 1 sError: 00A910 1 A2 00 ldx #0 00A912 1 A0 00 ldy #0 00A914 1 38 sec 00A915 1 60 rts 00A916 1 00A916 1 ExactSize: ;If equal, then DrvBlkCount1,DrvBlkCount0 is the 00A916 1 ; drive's exact size 00A916 1 AD 05 87 lda DrvBlkCount0 00A919 1 0D 06 87 ora DrvBlkCount1 00A91C 1 F0 F0 beq NoDrive ;can't have a 0-block device 00A91E 1 00A91E 1 AE 05 87 ldx DrvBlkCount0 00A921 1 AC 06 87 ldy DrvBlkCount1 00A924 1 sNoError: 00A924 1 A9 00 lda #0 00A926 1 18 clc ;no errors 00A927 1 60 rts 00A928 1 00A928 1 ;------------------------------------------------------------------------------ 00A928 1 ; IDEWaitReady - Waits for BUSY flag to clear, and returns DRQ bit status 00A928 1 ; 00A928 1 ; Input: 00A928 1 ; none 00A928 1 ; Ouput: 00A928 1 ; Carry flag set if DRQ bit is on 00A928 1 ; 00A928 1 ; ZeroPage Usage: 00A928 1 ; None 00A928 1 ; 00A928 1 ; CPU Registers changed: A, P 00A928 1 ; 00A928 1 IDEWaitReady: 00A928 1 AD FF AF lda ATAStatus 00A92B 1 30 FB bmi IDEWaitReady ;Wait for BUSY (bit 7) to be zero 00A92D 1 6A ror ;shift DRQ status bit into the Carry bit 00A92E 1 6A ror 00A92F 1 6A ror 00A930 1 6A ror 00A931 1 60 rts 00A932 1 00A932 1 ;------------------------------------------------------------------------------ 00A932 1 ; CheckDevice - Check to see if a device is attached to the interface. 00A932 1 ; 00A932 1 ; Input: 00A932 1 ; none 00A932 1 ; Output: 00A932 1 ; Carry flag: 0 = Device Present, 1 = Device Missing 00A932 1 ; 00A932 1 ; CPU Registers changed: A, P 00A932 1 ; 00A932 1 ; Checks to see if the drive status register is readable and equal to $50 00A932 1 ; If so, return with the Carry clear, otherwise return with the carry set. 00A932 1 ; Waits up to 10sec on a standard 1MHz system for drive to become ready. 00A932 1 ; 00A932 1 CheckDevice: 00A932 1 98 tya 00A933 1 48 pha 00A934 1 2C F2 AF bit ClearCSMask ;reset MASK bit in PLD for normal CS0 signaling 00A937 1 A9 E0 lda #$E0 ;$E0 = [1, LBA, 1, Drive, LBA 27-24] where 00A939 1 ; LBA=1, Drive=0 00A939 1 8D FE AF sta ATA_LBA27_24 ;Make sure ATA master drive is accessed 00A93C 1 00A93C 1 A0 00 ldy #0 00A93E 1 chkLoop: 00A93E 1 AD FF AF lda ATAStatus 00A941 1 29 D0 and #%11010000 00A943 1 C9 50 cmp #$50 ;if BUSY= 0 and RDY=1 and DSC=1 00A945 1 F0 0D beq DeviceFound 00A947 1 A9 C5 lda #WAIT_100ms 00A949 1 20 58 A9 jsr Wait ;Wait 100ms for device to be ready 00A94C 1 C8 iny 00A94D 1 C0 64 cpy #100 ;Wait up to 10 seconds for drive to be ready 00A94F 1 D0 ED bne chkLoop 00A951 1 00A951 1 38 sec ;set c = 1 if drive is not attached 00A952 1 B0 01 bcs DeviceExit 00A954 1 00A954 1 DeviceFound: 00A954 1 18 clc ;set c = 0 if drive is attached 00A955 1 00A955 1 DeviceExit: 00A955 1 68 pla 00A956 1 A8 tay 00A957 1 60 rts 00A958 1 .endif 00A958 1 00A958 1 ;------------------------------------------------------------------------------ 00A958 1 ; Wait - Copy of Apple's wait routine. Can't use ROM based routine in case 00A958 1 ; ROM is not active when we need it. 00A958 1 ; 00A958 1 ; Input: 00A958 1 ; A = desired delay time, where Delay(us) = .5(5A^2 + 27A + 26) 00A958 1 ; or more usefully: A = (Delay[in uS]/2.5 + 2.09)^.5 - 2.7 00A958 1 ; 00A958 1 ; CPU Registers changed: A, P 00A958 1 ; 00A958 1 Wait: 00A958 1 38 sec 00A959 1 00A959 1 Wait2: 00A959 1 48 pha 00A95A 1 00A95A 1 Wait3: 00A95A 1 E9 01 sbc #1 00A95C 1 D0 FC bne Wait3 00A95E 1 68 pla 00A95F 1 E9 01 sbc #1 00A961 1 D0 F6 bne Wait2 00A963 1 60 rts 00A964 1 00A964 1 00A964 1 .if APPLE2 00A964 1 ;------------------------------------------------------------------------------ 00A964 1 ; ReadOrWriteBlockAppleII 00A964 1 ; 00A964 1 ; Input: pdCommandCode, pdBlockNumber, pdIOBuffer 00A964 1 ; Result: CLC for success, SEC/A=error 00A964 1 ; 00A964 1 ReadOrWriteBlockAppleII: 00A964 1 lda pdIOBufferHigh 00A964 1 ldx pdIOBufferLow 00A964 1 sta rw_buffer+1 00A964 1 stx rw_buffer 00A964 1 lda pdBlockNumberHigh 00A964 1 ldx pdBlockNumberLow 00A964 1 sta rw_block+1 00A964 1 stx rw_block 00A964 1 lda pdCommandCode 00A964 1 cmp #PRODOS_READ 00A964 1 beq ReadBlockA2 00A964 1 cmp #PRODOS_WRITE 00A964 1 beq WriteBlockA2 00A964 1 cmp #PRODOS_STATUS 00A964 1 beq StatusA2 00A964 1 lda #PRODOS_IO_ERROR 00A964 1 sec 00A964 1 rts 00A964 1 00A964 1 ReadBlockA2: 00A964 1 jsr $bf00 00A964 1 .byte $80 00A964 1 .word rw_parms 00A964 1 rts 00A964 1 00A964 1 WriteBlockA2: 00A964 1 jsr $bf00 00A964 1 .byte $81 00A964 1 .word rw_parms 00A964 1 rts 00A964 1 00A964 1 rw_parms: 00A964 1 .byte 3 00A964 1 .byte $D0 ;slot 5, drive 2 00A964 1 rw_buffer: 00A964 1 .word 0 00A964 1 rw_block: 00A964 1 .word 0 00A964 1 00A964 1 StatusA2: 00A964 1 lda DriveNumber 00A964 1 cmp #2 00A964 1 bcs @err 00A964 1 cmp #1 00A964 1 beq @status1 00A964 1 @status0: 00A964 1 ldy #$12 00A964 1 ldx #$34 00A964 1 lda #0 00A964 1 clc 00A964 1 rts 00A964 1 @status1: 00A964 1 ldy #$23 00A964 1 ldx #$45 00A964 1 lda #0 00A964 1 clc 00A964 1 rts 00A964 1 @err: 00A964 1 lda #PRODOS_OFFLINE 00A964 1 sec 00A964 1 rts 00A964 1 .endif 00A964 1 00A964 1 ;------------------------------------------------------------------------------ 00A964 1 ; LogBlockOperationBefore 00A964 1 ; 00A964 1 ; Input: pdCommandCode, pdIOBuffer, pdBlockNumber 00A964 1 ; Result: Message displayed, such as: 00A964 1 ; [READ $0002 @ $7A00 00A964 1 ; [WRITE $0006 @ $7E00 00A964 1 ; [STATUS $00 00A964 1 ; 00A964 1 LogBlockOperationBefore: 00A964 1 A5 42 lda pdCommandCode 00A966 1 C9 01 cmp #PRODOS_READ 00A968 1 F0 12 beq @read 00A96A 1 C9 02 cmp #PRODOS_WRITE 00A96C 1 F0 1C beq @write 00A96E 1 C9 00 cmp #PRODOS_STATUS 00A970 1 F0 38 beq @status 00A972 1 20 8C 96 jsr DispString 00A975 1 5B 3F 3F 3F .byte "[??? ",0 00A979 1 20 00 00A97B 1 60 rts 00A97C 1 @read: 00A97C 1 20 8C 96 jsr DispString 00A97F 1 5B 52 45 41 .byte "[READ ",0 00A983 1 44 20 20 00 00A987 1 4C 95 A9 jmp @common 00A98A 1 @write: 00A98A 1 20 8C 96 jsr DispString 00A98D 1 5B 57 52 49 .byte "[WRITE ",0 00A991 1 54 45 20 00 00A995 1 @common: 00A995 1 A5 47 lda pdBlockNumberHigh 00A997 1 A6 46 ldx pdBlockNumberLow 00A999 1 20 15 9A jsr PrintHexAX 00A99C 1 20 8C 96 jsr DispString 00A99F 1 20 40 20 00 .byte " @ ",0 00A9A3 1 A5 45 lda pdIOBufferHigh 00A9A5 1 A6 44 ldx pdIOBufferLow 00A9A7 1 4C 15 9A jmp PrintHexAX 00A9AA 1 @status: 00A9AA 1 20 8C 96 jsr DispString 00A9AD 1 5B 53 54 41 .byte "[STATUS ",0 00A9B1 1 54 55 53 20 00A9B5 1 00 00A9B6 1 AD 03 87 lda DriveNumber 00A9B9 1 4C 25 98 jmp DispByteWithDollarSign 00A9BC 1 00A9BC 1 ;------------------------------------------------------------------------------ 00A9BC 1 ; LogBlockOperationAfter 00A9BC 1 ; 00A9BC 1 ; If CLC, just displays the "]",CR to end the log message. 00A9BC 1 ; If SEC, displays the error code in A as well. 00A9BC 1 ; 00A9BC 1 ; Preserves: A, P. 00A9BC 1 ; 00A9BC 1 LogBlockOperationAfter: 00A9BC 1 08 php 00A9BD 1 48 pha 00A9BE 1 90 0D bcc @noError 00A9C0 1 20 8C 96 jsr DispString 00A9C3 1 20 45 52 52 .byte " ERR=$",0 00A9C7 1 3D 24 00 00A9CA 1 20 2A 98 jsr DispByte 00A9CD 1 @noError: 00A9CD 1 20 8C 96 jsr DispString 00A9D0 1 5D 8D 00 .byte "]",CR,0 00A9D3 1 68 pla 00A9D4 1 28 plp 00A9D5 1 60 rts 00A9D6 1 00A9D6 1 00A9D6 1 ;------------------------------------------------------------------------------ 00A9D6 1 ; At the end of the 8K of ROM, put our ID bytes and a version number. 00A9D6 1 ;------------------------------------------------------------------------------ 00A9D6 1 xx xx xx xx .res Origin+$2000-32-4-* 00A9DA 1 xx xx xx xx 00A9DE 1 xx xx xx xx 00A9E2 1 xx xx xx xx 00A9E6 1 xx xx xx xx 00A9EA 1 xx xx xx xx 00A9EE 1 xx xx xx xx 00A9F2 1 xx xx xx xx 00A9F6 1 xx xx xx xx 00A9FA 1 xx xx xx xx 00A9FE 1 xx xx xx xx 00AA02 1 xx xx xx xx 00AA06 1 xx xx xx xx 00AA0A 1 xx xx xx xx 00AA0E 1 xx xx xx xx 00AA12 1 xx xx xx xx 00AA16 1 xx xx xx xx 00AA1A 1 xx xx xx xx 00AA1E 1 xx xx xx xx 00AA22 1 xx xx xx xx 00AA26 1 xx xx xx xx 00AA2A 1 xx xx xx xx 00AA2E 1 xx xx xx xx 00AA32 1 xx xx xx xx 00AA36 1 xx xx xx xx 00AA3A 1 xx xx xx xx 00AA3E 1 xx xx xx xx 00AA42 1 xx xx xx xx 00AA46 1 xx xx xx xx 00AA4A 1 xx xx xx xx 00AA4E 1 xx xx xx xx 00AA52 1 xx xx xx xx 00AA56 1 xx xx xx xx 00AA5A 1 xx xx xx xx 00AA5E 1 xx xx xx xx 00AA62 1 xx xx xx xx 00AA66 1 xx xx xx xx 00AA6A 1 xx xx xx xx 00AA6E 1 xx xx xx xx 00AA72 1 xx xx xx xx 00AA76 1 xx xx xx xx 00AA7A 1 xx xx xx xx 00AA7E 1 xx xx xx xx 00AA82 1 xx xx xx xx 00AA86 1 xx xx xx xx 00AA8A 1 xx xx xx xx 00AA8E 1 xx xx xx xx 00AA92 1 xx xx xx xx 00AA96 1 xx xx xx xx 00AA9A 1 xx xx xx xx 00AA9E 1 xx xx xx xx 00AAA2 1 xx xx xx xx 00AAA6 1 xx xx xx xx 00AAAA 1 xx xx xx xx 00AAAE 1 xx xx xx xx 00AAB2 1 xx xx xx xx 00AAB6 1 xx xx xx xx 00AABA 1 xx xx xx xx 00AABE 1 xx xx xx xx 00AAC2 1 xx xx xx xx 00AAC6 1 xx xx xx xx 00AACA 1 xx xx xx xx 00AACE 1 xx xx xx xx 00AAD2 1 xx xx xx xx 00AAD6 1 xx xx xx xx 00AADA 1 xx xx xx xx 00AADE 1 xx xx xx xx 00AAE2 1 xx xx xx xx 00AAE6 1 xx xx xx xx 00AAEA 1 xx xx xx xx 00AAEE 1 xx xx xx xx 00AAF2 1 xx xx xx xx 00AAF6 1 xx xx xx xx 00AAFA 1 xx xx xx xx 00AAFE 1 xx xx xx xx 00AB02 1 xx xx xx xx 00AB06 1 xx xx xx xx 00AB0A 1 xx xx xx xx 00AB0E 1 xx xx xx xx 00AB12 1 xx xx xx xx 00AB16 1 xx xx xx xx 00AB1A 1 xx xx xx xx 00AB1E 1 xx xx xx xx 00AB22 1 xx xx xx xx 00AB26 1 xx xx xx xx 00AB2A 1 xx xx xx xx 00AB2E 1 xx xx xx xx 00AB32 1 xx xx xx xx 00AB36 1 xx xx xx xx 00AB3A 1 xx xx xx xx 00AB3E 1 xx xx xx xx 00AB42 1 xx xx xx xx 00AB46 1 xx xx xx xx 00AB4A 1 xx xx xx xx 00AB4E 1 xx xx xx xx 00AB52 1 xx xx xx xx 00AB56 1 xx xx xx xx 00AB5A 1 xx xx xx xx 00AB5E 1 xx xx xx xx 00AB62 1 xx xx xx xx 00AB66 1 xx xx xx xx 00AB6A 1 xx xx xx xx 00AB6E 1 xx xx xx xx 00AB72 1 xx xx xx xx 00AB76 1 xx xx xx xx 00AB7A 1 xx xx xx xx 00AB7E 1 xx xx xx xx 00AB82 1 xx xx xx xx 00AB86 1 xx xx xx xx 00AB8A 1 xx xx xx xx 00AB8E 1 xx xx xx xx 00AB92 1 xx xx xx xx 00AB96 1 xx xx xx xx 00AB9A 1 xx xx xx xx 00AB9E 1 xx xx xx xx 00ABA2 1 xx xx xx xx 00ABA6 1 xx xx xx xx 00ABAA 1 xx xx xx xx 00ABAE 1 xx xx xx xx 00ABB2 1 xx xx xx xx 00ABB6 1 xx xx xx xx 00ABBA 1 xx xx xx xx 00ABBE 1 xx xx xx xx 00ABC2 1 xx xx xx xx 00ABC6 1 xx xx xx xx 00ABCA 1 xx xx xx xx 00ABCE 1 xx xx xx xx 00ABD2 1 xx xx xx xx 00ABD6 1 xx xx xx xx 00ABDA 1 xx xx xx xx 00ABDE 1 xx xx xx xx 00ABE2 1 xx xx xx xx 00ABE6 1 xx xx xx xx 00ABEA 1 xx xx xx xx 00ABEE 1 xx xx xx xx 00ABF2 1 xx xx xx xx 00ABF6 1 xx xx xx xx 00ABFA 1 xx xx xx xx 00ABFE 1 xx xx xx xx 00AC02 1 xx xx xx xx 00AC06 1 xx xx xx xx 00AC0A 1 xx xx xx xx 00AC0E 1 xx xx xx xx 00AC12 1 xx xx xx xx 00AC16 1 xx xx xx xx 00AC1A 1 xx xx xx xx 00AC1E 1 xx xx xx xx 00AC22 1 xx xx xx xx 00AC26 1 xx xx xx xx 00AC2A 1 xx xx xx xx 00AC2E 1 xx xx xx xx 00AC32 1 xx xx xx xx 00AC36 1 xx xx xx xx 00AC3A 1 xx xx xx xx 00AC3E 1 xx xx xx xx 00AC42 1 xx xx xx xx 00AC46 1 xx xx xx xx 00AC4A 1 xx xx xx xx 00AC4E 1 xx xx xx xx 00AC52 1 xx xx xx xx 00AC56 1 xx xx xx xx 00AC5A 1 xx xx xx xx 00AC5E 1 xx xx xx xx 00AC62 1 xx xx xx xx 00AC66 1 xx xx xx xx 00AC6A 1 xx xx xx xx 00AC6E 1 xx xx xx xx 00AC72 1 xx xx xx xx 00AC76 1 xx xx xx xx 00AC7A 1 xx xx xx xx 00AC7E 1 xx xx xx xx 00AC82 1 xx xx xx xx 00AC86 1 xx xx xx xx 00AC8A 1 xx xx xx xx 00AC8E 1 xx xx xx xx 00AC92 1 xx xx xx xx 00AC96 1 xx xx xx xx 00AC9A 1 xx xx xx xx 00AC9E 1 xx xx xx xx 00ACA2 1 xx xx xx xx 00ACA6 1 xx xx xx xx 00ACAA 1 xx xx xx xx 00ACAE 1 xx xx xx xx 00ACB2 1 xx xx xx xx 00ACB6 1 xx xx xx xx 00ACBA 1 xx xx xx xx 00ACBE 1 xx xx xx xx 00ACC2 1 xx xx xx xx 00ACC6 1 xx xx xx xx 00ACCA 1 xx xx xx xx 00ACCE 1 xx xx xx xx 00ACD2 1 xx xx xx xx 00ACD6 1 xx xx xx xx 00ACDA 1 xx xx xx xx 00ACDE 1 xx xx xx xx 00ACE2 1 xx xx xx xx 00ACE6 1 xx xx xx xx 00ACEA 1 xx xx xx xx 00ACEE 1 xx xx xx xx 00ACF2 1 xx xx xx xx 00ACF6 1 xx xx xx xx 00ACFA 1 xx xx xx xx 00ACFE 1 xx xx xx xx 00AD02 1 xx xx xx xx 00AD06 1 xx xx xx xx 00AD0A 1 xx xx xx xx 00AD0E 1 xx xx xx xx 00AD12 1 xx xx xx xx 00AD16 1 xx xx xx xx 00AD1A 1 xx xx xx xx 00AD1E 1 xx xx xx xx 00AD22 1 xx xx xx xx 00AD26 1 xx xx xx xx 00AD2A 1 xx xx xx xx 00AD2E 1 xx xx xx xx 00AD32 1 xx xx xx xx 00AD36 1 xx xx xx xx 00AD3A 1 xx xx xx xx 00AD3E 1 xx xx xx xx 00AD42 1 xx xx xx xx 00AD46 1 xx xx xx xx 00AD4A 1 xx xx xx xx 00AD4E 1 xx xx xx xx 00AD52 1 xx xx xx xx 00AD56 1 xx xx xx xx 00AD5A 1 xx xx xx xx 00AD5E 1 xx xx xx xx 00AD62 1 xx xx xx xx 00AD66 1 xx xx xx xx 00AD6A 1 xx xx xx xx 00AD6E 1 xx xx xx xx 00AD72 1 xx xx xx xx 00AD76 1 xx xx xx xx 00AD7A 1 xx xx xx xx 00AD7E 1 xx xx xx xx 00AD82 1 xx xx xx xx 00AD86 1 xx xx xx xx 00AD8A 1 xx xx xx xx 00AD8E 1 xx xx xx xx 00AD92 1 xx xx xx xx 00AD96 1 xx xx xx xx 00AD9A 1 xx xx xx xx 00AD9E 1 xx xx xx xx 00ADA2 1 xx xx xx xx 00ADA6 1 xx xx xx xx 00ADAA 1 xx xx xx xx 00ADAE 1 xx xx xx xx 00ADB2 1 xx xx xx xx 00ADB6 1 xx xx xx xx 00ADBA 1 xx xx xx xx 00ADBE 1 xx xx xx xx 00ADC2 1 xx xx xx xx 00ADC6 1 xx xx xx xx 00ADCA 1 xx xx xx xx 00ADCE 1 xx xx xx xx 00ADD2 1 xx xx xx xx 00ADD6 1 xx xx xx xx 00ADDA 1 xx xx xx xx 00ADDE 1 xx xx xx xx 00ADE2 1 xx xx xx xx 00ADE6 1 xx xx xx xx 00ADEA 1 xx xx xx xx 00ADEE 1 xx xx xx xx 00ADF2 1 xx xx xx xx 00ADF6 1 xx xx xx xx 00ADFA 1 xx xx xx xx 00ADFE 1 xx xx xx xx 00AE02 1 xx xx xx xx 00AE06 1 xx xx xx xx 00AE0A 1 xx xx xx xx 00AE0E 1 xx xx xx xx 00AE12 1 xx xx xx xx 00AE16 1 xx xx xx xx 00AE1A 1 xx xx xx xx 00AE1E 1 xx xx xx xx 00AE22 1 xx xx xx xx 00AE26 1 xx xx xx xx 00AE2A 1 xx xx xx xx 00AE2E 1 xx xx xx xx 00AE32 1 xx xx xx xx 00AE36 1 xx xx xx xx 00AE3A 1 xx xx xx xx 00AE3E 1 xx xx xx xx 00AE42 1 xx xx xx xx 00AE46 1 xx xx xx xx 00AE4A 1 xx xx xx xx 00AE4E 1 xx xx xx xx 00AE52 1 xx xx xx xx 00AE56 1 xx xx xx xx 00AE5A 1 xx xx xx xx 00AE5E 1 xx xx xx xx 00AE62 1 xx xx xx xx 00AE66 1 xx xx xx xx 00AE6A 1 xx xx xx xx 00AE6E 1 xx xx xx xx 00AE72 1 xx xx xx xx 00AE76 1 xx xx xx xx 00AE7A 1 xx xx xx xx 00AE7E 1 xx xx xx xx 00AE82 1 xx xx xx xx 00AE86 1 xx xx xx xx 00AE8A 1 xx xx xx xx 00AE8E 1 xx xx xx xx 00AE92 1 xx xx xx xx 00AE96 1 xx xx xx xx 00AE9A 1 xx xx xx xx 00AE9E 1 xx xx xx xx 00AEA2 1 xx xx xx xx 00AEA6 1 xx xx xx xx 00AEAA 1 xx xx xx xx 00AEAE 1 xx xx xx xx 00AEB2 1 xx xx xx xx 00AEB6 1 xx xx xx xx 00AEBA 1 xx xx xx xx 00AEBE 1 xx xx xx xx 00AEC2 1 xx xx xx xx 00AEC6 1 xx xx xx xx 00AECA 1 xx xx xx xx 00AECE 1 xx xx xx xx 00AED2 1 xx xx xx xx 00AED6 1 xx xx xx xx 00AEDA 1 xx xx xx xx 00AEDE 1 xx xx xx xx 00AEE2 1 xx xx xx xx 00AEE6 1 xx xx xx xx 00AEEA 1 xx xx xx xx 00AEEE 1 xx xx xx xx 00AEF2 1 xx xx xx xx 00AEF6 1 xx xx xx xx 00AEFA 1 xx xx xx xx 00AEFE 1 xx xx xx xx 00AF02 1 xx xx xx xx 00AF06 1 xx xx xx xx 00AF0A 1 xx xx xx xx 00AF0E 1 xx xx xx xx 00AF12 1 xx xx xx xx 00AF16 1 xx xx xx xx 00AF1A 1 xx xx xx xx 00AF1E 1 xx xx xx xx 00AF22 1 xx xx xx xx 00AF26 1 xx xx xx xx 00AF2A 1 xx xx xx xx 00AF2E 1 xx xx xx xx 00AF32 1 xx xx xx xx 00AF36 1 xx xx xx xx 00AF3A 1 xx xx xx xx 00AF3E 1 xx xx xx xx 00AF42 1 xx xx xx xx 00AF46 1 xx xx xx xx 00AF4A 1 xx xx xx xx 00AF4E 1 xx xx xx xx 00AF52 1 xx xx xx xx 00AF56 1 xx xx xx xx 00AF5A 1 xx xx xx xx 00AF5E 1 xx xx xx xx 00AF62 1 xx xx xx xx 00AF66 1 xx xx xx xx 00AF6A 1 xx xx xx xx 00AF6E 1 xx xx xx xx 00AF72 1 xx xx xx xx 00AF76 1 xx xx xx xx 00AF7A 1 xx xx xx xx 00AF7E 1 xx xx xx xx 00AF82 1 xx xx xx xx 00AF86 1 xx xx xx xx 00AF8A 1 xx xx xx xx 00AF8E 1 xx xx xx xx 00AF92 1 xx xx xx xx 00AF96 1 xx xx xx xx 00AF9A 1 xx xx xx xx 00AF9E 1 xx xx xx xx 00AFA2 1 xx xx xx xx 00AFA6 1 xx xx xx xx 00AFAA 1 xx xx xx xx 00AFAE 1 xx xx xx xx 00AFB2 1 xx xx xx xx 00AFB6 1 xx xx xx xx 00AFBA 1 xx xx xx xx 00AFBE 1 xx xx xx xx 00AFC2 1 xx xx xx xx 00AFC6 1 xx xx xx xx 00AFCA 1 xx xx xx xx 00AFCE 1 xx xx xx xx 00AFD2 1 xx xx xx xx 00AFD6 1 xx xx xx xx 00AFDA 1 xx xx 00AFDC 1 CF FA .byte $CF,$FA ; $AFFC, $AFFD = ID bytes 00AFDE 1 01 .byte OLDEST_COMPAT_VER ; $AFFE = oldest API-compatible version 00AFDF 1 01 .byte FIRMWARE_VER ; $AFFF = version 00AFE0 1 ;------------------------------------------------------------------------------ 00AFE0 1 ; END 00AFE0 1 ;------------------------------------------------------------------------------ 00AFE0 1 00AFE0 1