ca65 V2.11.0 - (C) Copyright 1998-2005 Ullrich von Bassewitz Main file : CFFAv2.0.s Current file: CFFAv2.0.s 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; ProDOS/SmartPort driver for CompactFlash/IDE Interface for Apple II computers 000000r 1 ; CFFA.s Version 2.0 - 27-Apr-2008 000000r 1 ; 000000r 1 ; Firmware Contributors: Email: 000000r 1 ; Chris Schumann cschumann@twp-llc.com 000000r 1 ; Rich Dreher rich@dreher.net 000000r 1 ; Dave Lyons dlyons@lyons42.com 000000r 1 ; 000000r 1 ; This code can be built to require a 65C02 or 65816, or to work on a 6502. 000000r 1 ; 000000r 1 ; Tools used to build this driver: 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) c:\firmware> ca65 -t apple2 --cpu 65C02 -l CFFA.s 000000r 1 ; 2) c:\firmware> ld65 -t apple2 CFFA.o -o CFFA.bin 000000r 1 ; 000000r 1 ; 3) If you have a newer, EEPROM-based CFFA card: 000000r 1 ; 000000r 1 ; Use CFFA.UTIL to copy the firmware onto the card. The Firmware Select 000000r 1 ; jumper allows two versions of the firmware on the card (for example, a 000000r 1 ; 6502 version and a 65C02 version). 000000r 1 ; 000000r 1 ; If you have made any changes to the "slot ROM" portion ($Cnxx), you 000000r 1 ; must update the slot ROM repeatedly, once for each Apple II slot where 000000r 1 ; you will ever use the CFFA card. After updating the last slot, then 000000r 1 ; you can update the Aux ROM, just once. 000000r 1 ; 000000r 1 ; -- or -- 000000r 1 ; 000000r 1 ; 3) If you have an older, EPROM-based CFFA: 000000r 1 ; 000000r 1 ; Because the EPROM can hold up to 8 user selectable versions of firmware 000000r 1 ; you must load CFFA.bin into your EPROM programmer with one of the 000000r 1 ; following offsets: 000000r 1 ; (Note: this offset has nothing to do with the card slot offsets) 000000r 1 ; 000000r 1 ; for driver #0: use offset $0000. Selected with: A14= IN, A13= IN, A12= IN 000000r 1 ; for driver #1: use offset $1000. Selected with: A14= IN, A13= IN, A12=OUT 000000r 1 ; for driver #2: use offset $2000. Selected with: A14= IN, A13=OUT, A12= IN 000000r 1 ; for driver #3: use offset $3000. Selected with: A14= IN, A13=OUT, A12=OUT 000000r 1 ; for driver #4: use offset $4000. Selected with: A14=OUT, A13= IN, A12= IN 000000r 1 ; for driver #5: use offset $5000. Selected with: A14=OUT, A13= IN, A12=OUT 000000r 1 ; for driver #6: use offset $6000. Selected with: A14=OUT, A13=OUT, A12= IN 000000r 1 ; for driver #7: use offset $7000. Selected with: A14=OUT, A13=OUT, A12=OUT 000000r 1 ; 000000r 1 ; where IN = jumper shorted, and OUT = jumper open 000000r 1 ; Driver #0 through #7 correspond to the user selectable 000000r 1 ; jumpers: J6 (A14, A13, A12) on the interface card. 000000r 1 ; 000000r 1 ; 4) Load as many firmware versions, up to 8, into the EPROM programmer as you 000000r 1 ; want. Remember that most programmers will, by default, clear all unused 000000r 1 ; memory to $FF when you load a binary file. You will need to disable that 000000r 1 ; feature after loading the first file. 000000r 1 ; 000000r 1 ; 5) Now you have an EPROM ready image to be programmed. 000000r 1 ; Using a standard 27C256 EPROM or similar, program your EPROM. 000000r 1 ; 000000r 1 ; Firmware Version History 000000r 1 ;------------------------- 000000r 1 ; Version 2.0 (February to April 2008, DAL) 000000r 1 ; - Started with version 1.20 source and merged in the 6502-specific changes. 000000r 1 ; - Merged in flow control changes from Dave Schmenk and made a further speed-up 000000r 1 ; in the Write loop. 000000r 1 ; - Added support for Dev0 and Dev1 (2 devices on the ATA bus) 000000r 1 ; - Added an interactive boot-time menu (press "M" during boot) 000000r 1 ; - Allows booting from any partition (on either device). On an EEPROM-based 000000r 1 ; CFFA, you can save the setting into EEPROM, or just use it temporarily. 000000r 1 ; - $C800 space contains user-configurable parameters: number of partitions, 000000r 1 ; default startup partition, 3-byte block offset allowing the partitions 000000r 1 ; to reside anywhere in the first 8GB of the device. 000000r 1 ; 000000r 1 ; 6502-only Version 1.0: (6502 version located at EPROM offset $4000, selection #4) 000000r 1 ; - Start of 6502 specific driver. Based on Version 1.2 spdrv.s driver 000000r 1 ; - Now works with 6502 CPU. Removed all 65C02 specific instruction from the ver 1.2 firmware 000000r 1 ; - NOTE: To work in 6502 based machine, logic CPLD version 1.3 or later is required. 000000r 1 ; - Changed error messages to upper case for Apple ]['s that don't support lower case. 000000r 1 ; - Set up slot specific behavior: Slot 5 has smartport enabled but will not autoboot. 000000r 1 ; All other slots have smartport disabled, but will autoboot in an Apple ][+ or ][e. 000000r 1 ; - Made 4th boot signature byte a parameter to boot code macro to ease slot specific setup. 000000r 1 ; - Changed GSOS_DRIVER signature to $10. This will prevent Dave Lyons' GS/OS driver from 000000r 1 ; loading should someone inadvertently use this firmware in a IIgs. 000000r 1 ; - Changed offsets for code loading with addition of .RES command 000000r 1 ; bin files can now be loaded in EPROM at normal 4K offsets:$0, $1000, $2000, etc, 000000r 1 ; instead of offsets $100, $1100, $2100, etc. 000000r 1 ; 000000r 1 ; Version 1.2 000000r 1 ; - Start of SmartPort driver. Based on Version 1.1 ProDOS driver 000000r 1 ; 000000r 1 ; Version 1.1 000000r 1 ; - dynamically calculate drive sizes in GetStatus function 000000r 1 ; - turn off interrupts in case boot code is called manually 000000r 1 ; - add cardID/firmware revision bytes: CFFA$xx 000000r 1 ; - added continuation of boot scan if device not present 000000r 1 ; - added continuation of boot scan if boot block code looks invalid 000000r 1 ; - reformatted this source file, removed tabs and added function headers 000000r 1 ; 000000r 1 ; 000000r 1 ; PLD Logic Firmware Information 000000r 1 ; ------------------------------- 000000r 1 ; This version of firmware assumes you are using PLD logic of at 000000r 1 ; least CPLD logic version 1.3. The source files for U6, the Altera PLD are: 000000r 1 ; Appleideinterface.gdf 000000r 1 ; Appleidelogic.tdf 000000r 1 ; 000000r 1 ; The programmer ready output file for the PLD logic is: 000000r 1 ; Appleideinterface.pof 000000r 1 ; 000000r 1 ; These files are not included with this code. 000000r 1 ; 000000r 1 ; Acknowledgements 000000r 1 ; ----------------- 000000r 1 ; Thanks to: 000000r 1 ; Chris Schuman - for his extensive initial development work 000000r 1 ; David Lyons - for technical information, many improvement ideas and 000000r 1 ; SmartPort code development, and v2.0 work 000000r 1 ; Dave Schmenk - for read/write speed-ups 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 000000r 1 .segment "EXEHDR" ; just to keep the linker happy 000000r 1 .segment "STARTUP" ; just to keep the linker happy 000000r 1 000000r 1 .linecont + ; Allow line continuations 000000r 1 000000r 1 .ifpc02 000000r 1 USE_65C02 = 1 000000r 1 .else 000000r 1 USE_65C02 = 0 000000r 1 .endif 000000r 1 000000r 1 REQUIRES_EEPROM = 1 000000r 1 IN_DEVELOPMENT = 0 ; show a non-"v" version letter 000000r 1 000000r 1 FULL_MENU = REQUIRES_EEPROM 000000r 1 000000r 1 MENU_IDENTIFY_DEVS = (USE_65C02 & FULL_MENU) ; 87 bytes (as of 15-Mar-2008) 000000r 1 MENU_DIGIT_INPUT = 0 ; 12 bytes 000000r 1 SMARTPORT_RAW_BLOCK_MAGIC = 0 ; 30 bytes 000000r 1 SMARTPORT_STATUS_D0_D1 = 0 ; 14 bytes 000000r 1 MENU_STAR_MONITOR = 0 ; 10 bytes 000000r 1 WRITE_PROTECT = 0 ; 18 bytes (incomplete, don't use) 000000r 1 000000r 1 .if WRITE_PROTECT 000000r 1 .error "WRITE_PROTECT isn't finished. It needs to affect status calls." 000000r 1 .endif 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Firmware Version Information 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 FIRMWARE_VER = $20 ; Version 2.0 (Version of this code) 000000r 1 SPDRIVERVERSION = $2000 ; Version of our SmartPort implementation (2.0) 000000r 1 ; 000000r 1 ; The GS/OS driver checks the GSOS_DRIVER byte to see if it is compatible with 000000r 1 ; this firmware. 000000r 1 ; 000000r 1 ; Increment by one, when something changes that would require a change 000000r 1 ; in the GS/OS driver. 000000r 1 ; $01 = ProDOS Driver supporting 2 drives. 000000r 1 ; $02 = SmartPort Driver supporting 4 drives 000000r 1 ; $03 = SmartPort Driver supporting 8 drives. NOTE: GS/OS driver won't load 000000r 1 ; $10 = 6502 version 1.0: ProDOS Driver supporting 2 drives. NOTE: GS/OS driver won't load 000000r 1 ; $11 = for CFFA firmware 2.0 (a future version of the GS/OS driver may load) 000000r 1 ; 000000r 1 GSOS_DRIVER = $11 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; ProDOS request Constants 000000r 1 PRODOS_STATUS = $00 000000r 1 PRODOS_READ = $01 000000r 1 PRODOS_WRITE = $02 000000r 1 PRODOS_FORMAT = $03 000000r 1 000000r 1 ; ProDOS Return Codes 000000r 1 PRODOS_NO_ERROR = $00 ; No error 000000r 1 PRODOS_BADCMD = $01 ; Bad Command 000000r 1 PRODOS_IO_ERROR = $27 ; I/O error 000000r 1 PRODOS_NO_DEVICE = $28 ; No Device Connected 000000r 1 PRODOS_WRITE_PROTECT = $2B ; Write Protected 000000r 1 PRODOS_BADBLOCK = $2D ; Invalid block number requested 000000r 1 PRODOS_OFFLINE = $2F ; Device off-line 000000r 1 000000r 1 ; SmartPort return codes 000000r 1 BAD_PARM_COUNT = $04 000000r 1 BAD_UNIT_NUMBER = $11 000000r 1 INTERRUPT_NOT_SUPT = $1F 000000r 1 BAD_STATUS_CODE = $21 000000r 1 000000r 1 ; ATA Commands Codes 000000r 1 ATACRead = $20 000000r 1 ATACWrite = $30 000000r 1 ATAIdentify = $EC 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Constants for Wait / ROMWait 000000r 1 ; Constant = (Delay[in uS]/2.5 + 2.09)^.5 - 2.7 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 WAIT_100ms = 197 000000r 1 WAIT_40ms = 124 000000r 1 WAIT_100us = 4 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; ASCII characters 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 BELL = $07 000000r 1 kLeftArrow = $08 000000r 1 kDownArrow = $0A 000000r 1 kUpArrow = $0B 000000r 1 CR = $0D 000000r 1 kRightArrow = $15 000000r 1 kEscape = $1B 000000r 1 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Apple II I/O locations 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 KEYBOARD = $C000 000000r 1 KBDSTROBE = $C010 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Slot I/O definitions 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 MSLOT = $7F8 ; Apple-defined -- $Cn for slot owning Aux ROM 000000r 1 000000r 1 IOBase = $C080 ; indexed with X = $n0 000000r 1 ATADataHigh = IOBase+0 000000r 1 000000r 1 ; SetCSMask / ClearCSMask - these strobe locations set and clear the MASK bit on 000000r 1 ; the CPLD that disables the CS0 line to the CompactFlash during the CPU read 000000r 1 ; cycles that occur before every CPU write cycle. (These "false reads" would 000000r 1 ; cause a device to double increment during a write.) 000000r 1 SetCSMask = IOBase+1 000000r 1 ClearCSMask = IOBase+2 000000r 1 WriteEEPROM = IOBase+3 ; with CPLD v2.1 - force-allow write $C800..C81F 000000r 1 NoWriteEEPROM = IOBase+4 ; with CPLD v2.1 - respect W/P jumper for $C800..C81F 000000r 1 000000r 1 ATADevCtrl = IOBase+6 ; when writing 000000r 1 ATAAltStatus = IOBase+6 ; when reading 000000r 1 ATADataLow = IOBase+8 000000r 1 ATAError = IOBase+9 000000r 1 ATASectorCnt = IOBase+$0A 000000r 1 ATASector = IOBase+$0B 000000r 1 ATACylinder = IOBase+$0C 000000r 1 ATACylinderH = IOBase+$0D 000000r 1 ATAHead = IOBase+$0E 000000r 1 ATACommand = IOBase+$0F ; when writing 000000r 1 ATAStatus = IOBase+$0F ; when reading 000000r 1 000000r 1 ; 000000r 1 ; "Screen hole" Scratchpad RAM base addresses. 000000r 1 ; Access using the Y register containg the slot number (lda DriveNumber,Y) 000000r 1 ; 000000r 1 DriveResetDone = $478 ; remember the device has been software reset 000000r 1 DriveNumber = $4F8 ; 0 for the first 32MB partition, 1 for the second, ... 000000r 1 BootDevice = $578 ; 0 = boot from Dev0, 1 = boot from Dev1 000000r 1 TempScreenHole = $5F8 000000r 1 PartitionsDev0 = $678 ; number of 32MB partitions on Dev0 000000r 1 PartitionsDev1 = $6F8 ; number of 32MB partitions on Dev1 000000r 1 DrvMiscFlags = $778 ; see kMiscXXX constants below 000000r 1 BootPartition = $7F8 ; physical index of boot partition (0 for no remapping) 000000r 1 000000r 1 kMiscRaw = $80 ; set this bit to read/write blocks on an entire device 000000r 1 kMiscDev1 = $40 ; set this bit in DrvMiscFlags,y to access Device 1 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Zero-page locations 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 CH = $24 000000r 1 INVFLG = $32 000000r 1 kNormalText = $FF 000000r 1 kInverseText = $3F 000000r 1 kFlashingText = $7F 000000r 1 000000r 1 zpt1 = $EF ; data at this location is saved/restored 000000r 1 bootError = $FF 000000r 1 000000r 1 ; Used only during the boot-time menu 000000r 1 menuSlot = spSlot 000000r 1 menuSlot16 = spSlotX16 000000r 1 menuRow = $82 000000r 1 menuMustSave = $83 000000r 1 menuJumpVectorH = $84 000000r 1 menuValues = $85 ; kMenuInteractiveRows (4) bytes 000000r 1 WriteOneByteToEEPROM = $90 ; 16 bytes 000000r 1 000000r 1 ; Saved and restored, used during Status calls to hold block counts 000000r 1 blockCount = $06 ; $06 to $08 (3 bytes) 000000r 1 000000r 1 ; ProDOS block interface locations 000000r 1 pdCommandCode = $42 000000r 1 pdUnitNumber = $43 000000r 1 pdIOBuffer = $44 000000r 1 pdIOBufferH = $45 000000r 1 pdBlockNumber = $46 000000r 1 pdBlockNumberH = $47 000000r 1 000000r 1 ; Arbitrary locations for Smartport data, 000000r 1 ; these locations are saved/restored before exit. 000000r 1 spCommandCode = pdCommandCode 000000r 1 000000r 1 spSlot = $40 ; menuSlot = spSlot 000000r 1 spSlotX16 = $41 ; menuSlot16 = spSlotX16 000000r 1 000000r 1 spParamList = $48 ; 2 bytes 000000r 1 spCmdList = $4A ; 2 bytes 000000r 1 spCSCode = $4C 000000r 1 spLastZP = spCSCode 000000r 1 000000r 1 spZeroPgArea = spSlot ; $40 000000r 1 spZeroPgSize = spLastZP-spZeroPgArea+1 000000r 1 000000r 1 StackBase = $100 000000r 1 000000r 1 ResetVector = $3F2 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; SmartPort constants 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Use these in SmartPort ReadBlock/WriteBlock calls for raw LBA blocks. 000000r 1 .if SMARTPORT_RAW_BLOCK_MAGIC 000000r 1 MagicRawBlocksDev0Unit = 127 000000r 1 MagicRawBlocksDev1Unit = 126 000000r 1 .endif 000000r 1 000000r 1 SMARTPORT_STATUS = 0 000000r 1 SMARTPORT_READ = 1 000000r 1 SMARTPORT_WRITE = 2 000000r 1 SMARTPORT_FORMAT = 3 000000r 1 SMARTPORT_CONTROL = 4 000000r 1 SMARTPORT_INIT = 5 000000r 1 SMARTPORT_OPEN = 6 000000r 1 SMARTPORT_CLOSE = 7 000000r 1 000000r 1 SP_STATUS_IDENT_DEV0 = $49 ; 'I' for Identify 000000r 1 SP_STATUS_IDENT_DEV1 = $48 ; identify the other device 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Apple II ROM entry points 000000r 1 ; 000000r 1 ; We can use these at boot time, but not while handling a call through 000000r 1 ; our ProDOS or SmartPort entry points, as the ROM may not be available. 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 AppleSoft = $E000 000000r 1 ResumeBootScan = $FABA ; SLOOP 000000r 1 TABV = $FB5B 000000r 1 SETPWRC = $FB6F ; fix up Reset vector 000000r 1 BELL1 = $FBDD ; delay, then beep 000000r 1 KEYIN = $FD0C 000000r 1 CROUT = $FD8E 000000r 1 PRBYTE = $FDDA 000000r 1 COUT = $FDED 000000r 1 SetKBD = $FE89 000000r 1 SetVID = $FE93 000000r 1 INIT = $FB2F 000000r 1 HOME = $FC58 000000r 1 ROMWAIT = $FCA8 000000r 1 SETNORM = $FE84 000000r 1 MONITOR = $FF69 000000r 1 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 ; Macros 000000r 1 ;------------------------------------------------------------------------------ 000000r 1 .macro BRA_OR_JMP Destination 000000r 1 .IF USE_65C02 000000r 1 bra Destination 000000r 1 .ELSE 000000r 1 jmp Destination 000000r 1 .ENDIF 000000r 1 .endmacro 000000r 1 000000r 1 .macro INC_A_OR_ADC1 000000r 1 .IF USE_65C02 000000r 1 inc a 000000r 1 .ELSE 000000r 1 clc 000000r 1 adc #1 000000r 1 .ENDIF 000000r 1 .endmacro 000000r 1 000000r 1 .macro DEC_A_OR_SBC1 000000r 1 .IF USE_65C02 000000r 1 dec a 000000r 1 .ELSE 000000r 1 sec 000000r 1 sbc #1 000000r 1 .ENDIF 000000r 1 .endmacro 000000r 1 000000r 1 .macro STZ_OR_LDA_STA mem 000000r 1 .IF USE_65C02 000000r 1 stz mem 000000r 1 .ELSE 000000r 1 lda #0 000000r 1 sta mem 000000r 1 .ENDIF 000000r 1 .endmacro 000000r 1 000000r 1 .macro STZ_OR_STA_ATADataHigh_X 000000r 1 .IF USE_65C02 000000r 1 stz ATADataHigh,x ; Clear high byte data latch 000000r 1 .ELSE 000000r 1 lda #0 000000r 1 sta ATADataHigh,x ; Clear high byte data latch 000000r 1 .ENDIF 000000r 1 .endmacro 000000r 1 000000r 1 .macro PHY_OR_TYA_PHA 000000r 1 .IF USE_65C02 000000r 1 phy 000000r 1 .ELSE 000000r 1 tya 000000r 1 pha ; save Y, it holds the $0n sratchpad RAM offset 000000r 1 .ENDIF 000000r 1 .endmacro 000000r 1 000000r 1 .macro PLY_OR_PLA_TAY 000000r 1 .IF USE_65C02 000000r 1 ply 000000r 1 .ELSE 000000r 1 pla 000000r 1 tay 000000r 1 .ENDIF 000000r 1 .endmacro 000000r 1 000000r 1 .macro ASSERT condition, string 000000r 1 .if condition 000000r 1 .else 000000r 1 .error string 000000r 1 .endif 000000r 1 .endmacro 000000r 1 000000r 1 .macro WARN condition, string 000000r 1 .if condition 000000r 1 .else 000000r 1 .warning string 000000r 1 .endif 000000r 1 .endmacro 000000r 1 000000r 1 ; String macro from 000000r 1 .macro HiBitString str 000000r 1 .repeat .strlen(str), i 000000r 1 .byte .strat(str,i) | $80 000000r 1 .endrepeat 000000r 1 .endmacro 000000r 1 000000r 1 ; SentinelString sets bit 7 on the final character in the string. 000000r 1 .macro SentinelString str 000000r 1 .repeat .strlen(str) - 1, i 000000r 1 .byte .strat(str,i) 000000r 1 .endrepeat 000000r 1 .byte .strat(str, .strlen(str) - 1) | $80 000000r 1 .endmacro 000000r 1 000000r 1 000000r 1 ;------------------------------------------------------------------------- 000000r 1 ; BEGIN ROM CONTENT 000000r 1 ;------------------------------------------------------------------------- 000000r 1 000000r 1 ;------------------------------------------------------------------------- 000000r 1 ; $C000 000000r 1 ; 000000r 1 ; The base address for this 4K of code is $C000. The first page ($C0xx) is 000000r 1 ; not available in the Apple II address space, so we'll just fill it with 000000r 1 ; something you might want to see if you have a copy of the firmware on 000000r 1 ; disk. 000000r 1 ;------------------------------------------------------------------------- 000000r 1 .ORG $C000 00C000 1 43 46 46 41 .byte "CFFA Firmware",CR,CR,CR 00C004 1 20 46 69 72 00C008 1 6D 77 61 72 00C010 1 53 65 65 20 .byte "See ." 00C014 1 3C 68 74 74 00C018 1 70 3A 2F 2F 00C036 1 0D 0D 0D 0D .byte CR,CR,CR,CR,CR,CR,CR,CR,CR,CR 00C03A 1 0D 0D 0D 0D 00C03E 1 0D 0D 00C040 1 56 65 72 73 .byte "Version " 00C044 1 69 6F 6E 20 00C048 1 32 2E 30 .byte $30+(FIRMWARE_VER/16), ".", $30+(FIRMWARE_VER & $F) 00C04B 1 20 66 6F 72 .byte " for " 00C04F 1 20 00C050 1 .IF USE_65C02 00C050 1 36 35 43 30 .byte "65C02" 00C054 1 32 00C055 1 .ELSE 00C055 1 .byte "6502" 00C055 1 .ENDIF 00C055 1 20 6F 72 20 .byte " or later.",CR,CR 00C059 1 6C 61 74 65 00C05D 1 72 2E 0D 0D 00C061 1 .IF REQUIRES_EEPROM 00C061 1 52 65 71 75 .byte "Requires CFFA with EEPROM, not EPROM.",CR,CR 00C065 1 69 72 65 73 00C069 1 20 43 46 46 00C088 1 .ELSE 00C088 1 .byte "Compatible with older EPROM-based CFFA cards.",CR,CR 00C088 1 .ENDIF 00C088 1 FF FF FF FF .RES $C100-*, $FF ; fill the rest of the $C0xx area (unused) 00C08C 1 FF FF FF FF 00C090 1 FF FF FF FF 00C100 1 00C100 1 ;------------------------------------------------------------------------------ 00C100 1 ; $C100 00C100 1 ; 00C100 1 ; Start of Peripheral Card ROM Space $Cn00 to $CnFF 00C100 1 ; 00C100 1 ; A macro (CnXX) is used here so that this code can be easily generated for 00C100 1 ; each slot, with minor variations. 00C100 1 ; 00C100 1 ; This is done because the hardware does not overlay the C1xx address space at 00C100 1 ; C2xx, C3xx, etc. automatically. Instead, the base address for the ROM is 00C100 1 ; $C000, and a read from $Cnxx is mapped to $0nxx in our ROM. 00C100 1 ; 00C100 1 ; ROM offsets $0000 to $00FF are not used. $0nxx is used for slot n. From 00C100 1 ; $0800 to $0FFE is the 2K expansion ROM. 00C100 1 ; 00C100 1 ; In an older EPROM-based CFFA card, the expansion ROM stops at $CEFF, and any 00C100 1 ; access to $CFxx turns off the expansion ROM -- so $0F00 to $0FFF are not used. 00C100 1 ; 00C100 1 ; In a newer EEPROM-based CFFA card, the expansion ROM continues all the way to 00C100 1 ; $CFFE, except that $CFEF and $CFFF both disable the expansion ROM. 00C100 1 ;------------------------------------------------------------------------------ 00C100 1 .macro CnXX SLOT, SIGNATURE_BYTE_4 00C100 1 .local P8DriverEntry 00C100 1 .local SmartPortEntry 00C100 1 .local commonEntry 00C100 1 .local Boot 00C100 1 .local MenuEntry 00C100 1 .local notMenu 00C100 1 .local PrepareForJumpToAuxROM 00C100 1 .local InvalidBootBlock 00C100 1 .local Error 00C100 1 .local ShowErrorMessage 00C100 1 .local ShowErrorMsgY 00C100 1 .local ErrorMessages 00C100 1 .local msgCheckTheDevice 00C100 1 .local msgNoBootBlock 00C100 1 .local msgCouldNotBootPartition 00C100 1 00C100 1 lda #$20 ; $20 is a signature for a drive to ProDOS 00C100 1 ldx #$00 ; $00 " 00C100 1 lda #$03 ; $03 " 00C100 1 ASSERT (SIGNATURE_BYTE_4 < $80), "SIGNATURE_BYTE_4 must be <$80 (BPL)" 00C100 1 lda #SIGNATURE_BYTE_4 ; $00 for SmartPort, $3C to look like a Disk II 00C100 1 bpl Boot ; NOTE: this must be a 2 byte instuction to keep the entry point offset correct 00C100 1 00C100 1 ;------------------- Non-boot P8 driver entry point --------------------- 00C100 1 ; ProDOS block device entry point (READ, WRITE, STATUS, FORMAT). 00C100 1 ;----------------------------------------------------------------------- 00C100 1 ASSERT (* = $C00A+$100*SLOT), "Should be at $Cn0A" 00C100 1 P8DriverEntry: ; At $Cn0A for best compatibility. 00C100 1 clc 00C100 1 bcc commonEntry 00C100 1 ASSERT (* = $C00D+$100*SLOT), "Should be at $Cn0D" 00C100 1 SmartPortEntry: ; At $Cn0D: SmartPort entry must be 3 bytes later 00C100 1 sec 00C100 1 commonEntry: 00C100 1 jsr PrepareForJumpToAuxROM 00C100 1 jmp P8_SmartPort_Handler 00C100 1 00C100 1 ;----------------------------------------------------------------------- 00C100 1 ; Boot 00C100 1 ; 00C100 1 ; Start up the Apple II from our device. Typically we will get here 00C100 1 ; because of a "boot scan" (the Apple II is searching for a bootable 00C100 1 ; device), or because of a direct PR#n for our slot. 00C100 1 ; 00C100 1 ; If the user has pressed the "menu snag" key, we'll display an 00C100 1 ; interactive settings menu. 00C100 1 ; 00C100 1 ; Otherwise, we'll try to read the boot block (block 0) from the 00C100 1 ; configured boot partition and then jump to the boot code. 00C100 1 ;----------------------------------------------------------------------- 00C100 1 Boot: 00C100 1 jsr PrepareForJumpToAuxROM ; also needed to access config params below 00C100 1 stx pdUnitNumber ; prepare to boot from "drive 1" 00C100 1 00C100 1 ; 00C100 1 ; Wait here (before the first CheckDevice) in case the CFFA RESET jumper 00C100 1 ; is enabled, or a Delkin Devices CF card never becomes ready. 00C100 1 ; 00C100 1 ldy BootTimeDelayTenths 00C100 1 @wasteTime: 00C100 1 lda #WAIT_100ms 00C100 1 jsr ROMWAIT 00C100 1 dey 00C100 1 bne @wasteTime 00C100 1 ; 00C100 1 ; Pressing a certain key (normally "M") at boot time brings up 00C100 1 ; the interactive menu. 00C100 1 ; 00C100 1 lda KEYBOARD 00C100 1 and MenuSnagMask 00C100 1 cmp MenuSnagKey 00C100 1 bne notMenu 00C100 1 00C100 1 .RES $C000+(SLOT*$100)+$30-*,$EA ; fill with NOPs to $Cn30 00C100 1 ; 00C100 1 ; MenuEntry -- available from the monitor as Cn30G 00C100 1 ; 00C100 1 ; (Because this is a supported user entry point, we can't assume that 00C100 1 ; we have already called PrepareForJumpToAuxROM above.) 00C100 1 ; 00C100 1 MenuEntry: 00C100 1 ASSERT MenuEntry=$C030+(SLOT*$100), "MenuEntry should be $Cn30" 00C100 1 jsr PrepareForJumpToAuxROM 00C100 1 jsr InteractiveMenu 00C100 1 00C100 1 notMenu: 00C100 1 ldy #PRODOS_READ ; Request: READ block 00C100 1 sty pdCommandCode 00C100 1 ASSERT PRODOS_READ=1, "PRODOS_READ must be 1" 00C100 1 dey ; Y = 0 00C100 1 sty pdBlockNumber ; ProDOS block $0000 (the bootloader block) 00C100 1 sty pdBlockNumberH 00C100 1 lda #$08 00C100 1 sta pdIOBufferH 00C100 1 sty pdIOBuffer ; Into Location $0800 00C100 1 ; Read the block by calling a special AuxROM entry point. 00C100 1 ; We could just use P8DriverEntry, but this allows future firmware 00C100 1 ; changes to the boot process without changes to the $Cn ROM. 00C100 1 jsr PrepareForJumpToAuxROM 00C100 1 jsr BootROM_ProDOS_Call 00C100 1 sta bootError ; store on zero page for error display 00C100 1 bcs Error 00C100 1 ldy $800 ; Check the first byte of boot loader code. 00C100 1 dey ; If bootload code is there, this byte = $01 00C100 1 bne InvalidBootBlock 00C100 1 lda $801 ; If second byte is a 0, it's invalid 00C100 1 beq InvalidBootBlock ; (we'd JMP to a BRK) 00C100 1 00C100 1 ldx pdUnitNumber ; X should contain the unit number when jumping 00C100 1 ; to the bootloader 00C100 1 jmp $801 ; Jump to the bootloader we just read. 00C100 1 00C100 1 00C100 1 ; If any error occured, like drive not present, check to see if we are in a 00C100 1 ; boot scan, if so re-enter scan routine, else drop to Applesoft, aborting boot. 00C100 1 InvalidBootBlock: 00C100 1 Error: 00C100 1 lda $00 00C100 1 bne @notScanning 00C100 1 lda $01 00C100 1 cmp MSLOT 00C100 1 bne @notScanning 00C100 1 jmp ResumeBootScan ; Re-enter Monitor's Autoscan Routine 00C100 1 @notScanning: 00C100 1 ; 00C100 1 ; The boot code must have been called manually because we are not in a slot scan. 00C100 1 ; 00C100 1 ShowErrorMessage: 00C100 1 jsr PrepareToShowErrorMessage ; clear screen and show banner 00C100 1 00C100 1 ldy #msgCheckTheDevice-ErrorMessages 00C100 1 ldx bootError 00C100 1 bne @someError 00C100 1 ldy #msgNoBootBlock-ErrorMessages 00C100 1 @someError: 00C100 1 jsr ShowErrorMsgY 00C100 1 00C100 1 txa 00C100 1 beq @skipDevNumber 00C100 1 00C100 1 ; show dev "0" or "1" after "Check device " 00C100 1 lda DrvMiscFlags+SLOT 00C100 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be bit 6" 00C100 1 asl a 00C100 1 asl a 00C100 1 lda #'0'+$80 00C100 1 adc #0 00C100 1 jsr COUT 00C100 1 @skipDevNumber: 00C100 1 00C100 1 ldy #msgCouldNotBootPartition-ErrorMessages 00C100 1 jsr ShowErrorMsgY 00C100 1 00C100 1 jsr PrepareForJumpToAuxROM ; set up X and Y for slot 00C100 1 jmp FinishBootTimeErrorMsg 00C100 1 00C100 1 ;----------------------------------------------------------------------- 00C100 1 ; ShowErrorMsgY 00C100 1 ; 00C100 1 ; Display a message from the boot-ROM table (ErrorMessages). 00C100 1 ; 00C100 1 ; Input: Y = offset from ErrorMessages. 00C100 1 ;----------------------------------------------------------------------- 00C100 1 ShowErrorMsgY: 00C100 1 @loop: 00C100 1 lda ErrorMessages,y 00C100 1 beq @done 00C100 1 jsr CaseSafeCOUT 00C100 1 iny 00C100 1 bne @loop 00C100 1 @done: 00C100 1 rts 00C100 1 00C100 1 ;----------------------------------------------------------------------- 00C100 1 ; PrepareForJumpToAuxROM 00C100 1 ; 00C100 1 ; Output - MSLOT = $Cn, X = $n0, Y = $0n 00C100 1 ; A = 0 00C100 1 ; Carry - preserved 00C100 1 ; 00C100 1 ; Turns off any other card's Aux ROM. 00C100 1 ; Resets the CFFA's CS0 mode. 00C100 1 ; 00C100 1 ; Verifies that the 2.0-or-later Aux ROM is present (in case the firmware 00C100 1 ; has been incompletely upgraded, or incompletely downgraded). 00C100 1 ;----------------------------------------------------------------------- 00C100 1 PrepareForJumpToAuxROM: 00C100 1 sta ClearCSMask+SLOT*16 ; reset MASK bit in PLD for normal CS0 signaling 00C100 1 00C100 1 ; We must set MSLOT to $Cn *before* touching $CFFF, in case an interrupt 00C100 1 ; occurs. The interrupt handler uses it to re-establish Aux ROM ownership. 00C100 1 lda #$C0+SLOT 00C100 1 sta MSLOT 00C100 1 bit $cfff ; turn off other ROM that might be on. 00C100 1 00C100 1 lda C820_Signature ; must have $CF if the Aux ROM is present 00C100 1 eor #$CF ; compare without disturbing the carry 00C100 1 bne @AuxROMTrouble 00C100 1 00C100 1 ldy #SLOT ; Y reg now has $0n for accessing scratchpad RAM 00C100 1 ldx #SLOT*16 ; X reg now has $n0 for indexing I/O 00C100 1 rts 00C100 1 00C100 1 ; The 2.0-and-later AuxROM is not there. Just BRK into the monitor. 00C100 1 @AuxROMTrouble: 00C100 1 jsr SetVID ; undo a PR#n to avoid an infinite reboot loop 00C100 1 brk 00C100 1 00C100 1 ;------------------------------------------------------------------------- 00C100 1 ; ErrorMessages table 00C100 1 ; 00C100 1 ; Each string ends with a 0 byte. 00C100 1 ;------------------------------------------------------------------------- 00C100 1 ErrorMessages: 00C100 1 msgCheckTheDevice: 00C100 1 .byte "Check device ",0 00C100 1 msgNoBootBlock: 00C100 1 .byte "No boot block",0 00C100 1 msgCouldNotBootPartition: 00C100 1 .byte ".",CR,CR,"Could not boot partition ",0 00C100 1 00C100 1 ;------------------------------------------------------------------------- 00C100 1 ; $CnF5 - $CnFF -- Boot ROM signature, version, and capability ID bytes 00C100 1 ; 00C100 1 ; $CnF5 to $CnFA were defined by CFFA, but should no longer be used. 00C100 1 ; Instead, see the similar bytes in the Aux ROM ($C8xx) area. 00C100 1 ; 00C100 1 ; $CnFB to $CnFF are defined by ProDOS and SmartPort. 00C100 1 ;------------------------------------------------------------------------- 00C100 1 .RES $C000+(SLOT*$100)+$F5-*,$77 ; skip to $CnF5 00C100 1 00C100 1 .byte $FF ; was GSOS_DRIVER value (see $C8xx version area) 00C100 1 .byte "CFFA", $FF ; $CnF6..CnFA: Card ID, old 1.x version # 00C100 1 00C100 1 ; $CnFB: SmartPort status byte 00C100 1 .byte $0 ; Not Extended; not SCSI; not RAM card 00C100 1 ; Even if not supporting SmartPort, we need a 00C100 1 ; zero at $CnFB so Apple's RAMCard driver 00C100 1 ; doesn't mistake us for a "Slinky" memory 00C100 1 ; card. 00C100 1 00C100 1 ; Data table for ProDOS drive scan 00C100 1 ; $CnFC/FD = disk capacity, if zero use status command to determine 00C100 1 .word $0000 ; $CnFC-D: A zero here will cause ProDOS to 00C100 1 ; rely on the STATUS command to determine volume size 00C100 1 00C100 1 ; $CnFE = status bits (BAP p7-14) 00C100 1 ; 7 = medium is removable 00C100 1 ; 6 = device is interruptable 00C100 1 ; 5-4 = number of volumes (0..3 means 1..4) 00C100 1 ; 3 = device supports Format call 00C100 1 ; 2 = device can be written to 00C100 1 ; 1 = device can be read from (must be 1) 00C100 1 ; 0 = device status can be read (must be 1) 00C100 1 .byte %00010111 ; $CnFE: support 2 ProDOS drives 00C100 1 00C100 1 ; $CnFF = LSB of block driver 00C100 1 .byte 0 00CB8D 1 AA tax 00CB8E 1 00CB8E 1 68 pla 00CB8F 1 85 EF sta zpt1 00CB91 1 68 pla 00CB92 1 85 45 sta pdIOBufferH 00CB94 1 00CB94 1 68 pla 00CB95 1 85 46 sta pdBlockNumber 00CB97 1 68 pla 00CB98 1 85 47 sta pdBlockNumberH 00CB9A 1 00CB9A 1 8A txa 00CB9B 1 60 rts 00CB9C 1 00CB9C 1 @PLP_ioError: 00CB9C 1 28 plp 00CB9D 1 @ioError: 00CB9D 1 A9 27 lda #PRODOS_IO_ERROR 00CB9F 1 D0 EA bne @outErrorA 00CBA1 1 00CBA1 1 ;------------------------------------------------------------------------------ 00CBA1 1 ; Block2LBA - Translates ProDOS block# into LBA and programs device's task file 00CBA1 1 ; registers. 00CBA1 1 ; 00CBA1 1 ; Input: 00CBA1 1 ; pd Command Block Data $42 - $47 00CBA1 1 ; DrvMiscFlags,y has been set up to specify Dev0 or Dev1 00CBA1 1 ; DriveNumber,y specifies a 32MB chunk (physical partition number) 00CBA1 1 ; X = slot * 16 ($n0) 00CBA1 1 ; Y = slot 00CBA1 1 ; 00CBA1 1 ; Ouput: 00CBA1 1 ; None 00CBA1 1 ; 00CBA1 1 ; ZeroPage Usage: 00CBA1 1 ; None 00CBA1 1 ; 00CBA1 1 ; CPU Registers changed: A, P 00CBA1 1 ; 00CBA1 1 ; This function translates the block number sent in the ProDOS request 00CBA1 1 ; packet, into an ATA Logical Block Address (LBA). 00CBA1 1 ; The least significant 16 bits becomes the ProDOS block#. 00CBA1 1 ; The most significant 16 becomes the ProDOS Drive # 00CBA1 1 ; 00CBA1 1 ; A ProDOS block and a ATA sector are both 512 bytes. 00CBA1 1 ; 00CBA1 1 ; Logical Block Mode, the Logical Block Address is interpreted as follows: 00CBA1 1 ; LBA07-LBA00: Sector Number Register D7-D0. 00CBA1 1 ; LBA15-LBA08: Cylinder Low Register D7-D0. 00CBA1 1 ; LBA23-LBA16: Cylinder High Register D7-D0. 00CBA1 1 ; LBA27-LBA24: Drive/Head Register bits HS3-HS0. 00CBA1 1 ;------------------------------------------------------------------------------ 00CBA1 1 Block2LBA: 00CBA1 1 20 00 CD jsr WaitReady_SetATAHeadFromMiscDrvFlags 00CBA4 1 00CBA4 1 A9 01 lda #1 00CBA6 1 9D 8A C0 sta ATASectorCnt,x 00CBA9 1 ; 00CBA9 1 ; Add BlockOffset to the ProDOS block number to offset the first drive block we 00CBA9 1 ; use. This keeps the device's first BlockOffset blocks free, which usually 00CBA9 1 ; includes a MBR at block 0. 00CBA9 1 ; 00CBA9 1 B9 78 07 lda DrvMiscFlags,y ; bit 7 = raw block access 00CBAC 1 ASSERT kMiscRaw=$80, "kMiscRaw must be $80 so we can test it with BMI" 00CBAC 1 .if SMARTPORT_RAW_BLOCK_MAGIC 00CBAC 1 bmi @rawBlocks 00CBAC 1 .endif 00CBAC 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be $40 for this test" 00CBAC 1 0A asl a ; since A<$80, this clears the carry 00CBAD 1 30 1A bmi @dev1 00CBAF 1 00CBAF 1 ; clc 00CBAF 1 A5 46 lda pdBlockNumber 00CBB1 1 6D 0F C8 adc BlockOffsetDev0 00CBB4 1 9D 8B C0 sta ATASector,x ; store ProDOS Low block # into LBA 0-7 00CBB7 1 00CBB7 1 A5 47 lda pdBlockNumberH 00CBB9 1 6D 10 C8 adc BlockOffsetDev0+1 00CBBC 1 9D 8C C0 sta ATACylinder,x ; store ProDOS High block # into LBA 15-8 00CBBF 1 00CBBF 1 AD 11 C8 lda BlockOffsetDev0+2 00CBC2 1 @addDriveAndStoreCylinderH: 00CBC2 1 79 F8 04 adc DriveNumber,y 00CBC5 1 9D 8D C0 sta ATACylinderH,x ; store LBA bits 23-16 00CBC8 1 60 rts 00CBC9 1 00CBC9 1 @dev1: 00CBC9 1 ; clc 00CBC9 1 A5 46 lda pdBlockNumber 00CBCB 1 6D 12 C8 adc BlockOffsetDev1 00CBCE 1 9D 8B C0 sta ATASector,x ; store ProDOS Low block # into LBA 0-7 00CBD1 1 00CBD1 1 A5 47 lda pdBlockNumberH 00CBD3 1 6D 13 C8 adc BlockOffsetDev1+1 00CBD6 1 9D 8C C0 sta ATACylinder,x ; store ProDOS High block # into LBA 15-8 00CBD9 1 00CBD9 1 AD 14 C8 lda BlockOffsetDev1+2 00CBDC 1 80 E4 BRA_OR_JMP @addDriveAndStoreCylinderH 00CBDE 1 00CBDE 1 .if SMARTPORT_RAW_BLOCK_MAGIC 00CBDE 1 @rawBlocks: 00CBDE 1 lda pdBlockNumber 00CBDE 1 sta ATASector,x ; store ProDOS Low block # into LBA 0-7 00CBDE 1 lda pdBlockNumberH 00CBDE 1 sta ATACylinder,x ; store ProDOS High block # into LBA 15-8 00CBDE 1 lda DriveNumber,y 00CBDE 1 BRA_OR_JMP @storeCylinderH 00CBDE 1 .endif 00CBDE 1 00CBDE 1 ;------------------------------------------------------------------------------ 00CBDE 1 ; ResetBusIfFirstTime_ClearMiscFlags 00CBDE 1 ; 00CBDE 1 ; Reset the bus (both devices) once, the first time the driver is called. 00CBDE 1 ; 00CBDE 1 ; ide_devctrl Bit 2 = Software Reset, Bit 1 = nIEN (enable assertion of INTRQ) 00CBDE 1 ; 00CBDE 1 ; Input: 00CBDE 1 ; X = slot * 16 ($n0) 00CBDE 1 ; Y = slot 00CBDE 1 ; 00CBDE 1 ; ZeroPage Usage: 00CBDE 1 ; None 00CBDE 1 ; 00CBDE 1 ; CPU Registers changed: A, P 00CBDE 1 ;------------------------------------------------------------------------------ 00CBDE 1 INIT_DONE_SIG = $A5 00CBDE 1 00CBDE 1 ResetBusIfFirstTime_ClearMiscFlags: 00CBDE 1 B9 78 04 lda DriveResetDone,Y 00CBE1 1 C9 A5 cmp #INIT_DONE_SIG 00CBE3 1 F0 45 beq noNeedToResetBus 00CBE5 1 00CBE5 1 ResetBusAlways_ClearMiscFlags: 00CBE5 1 AD 03 C8 lda DefaultBootPartition 00CBE8 1 3A DEC_A_OR_SBC1 00CBE9 1 99 F8 07 sta BootPartition,y 00CBEC 1 AD 02 C8 lda DefaultBootDevice 00CBEF 1 99 78 05 sta BootDevice,y 00CBF2 1 00CBF2 1 AD 00 C8 lda Max32MBPartitionsDev0 00CBF5 1 99 78 06 sta PartitionsDev0,y 00CBF8 1 AD 01 C8 lda Max32MBPartitionsDev1 00CBFB 1 99 F8 06 sta PartitionsDev1,y 00CBFE 1 19 78 06 ora PartitionsDev0,y 00CC01 1 F0 22 beq @totalMaxPartitionsZero 00CC03 1 ; 00CC03 1 ; Reset the ATA bus (applies to both devices at once) 00CC03 1 ; 00CC03 1 BD 82 C0 lda ClearCSMask,x ; reset MASK bit in PLD for normal CS0 signaling 00CC06 1 00CC06 1 9E 80 C0 STZ_OR_STA_ATADataHigh_X 00CC09 1 00CC09 1 AD 0E C8 lda ConfigOptionBits 00CC0C 1 30 14 bmi @skipBusReset 00CC0E 1 00CC0E 1 A9 06 lda #$06 ; SRST (software reset) = 1, Disable INTRQ=1 00CC10 1 9D 86 C0 sta ATADevCtrl,x 00CC13 1 ; 00CC13 1 ; Per ATA-6 sec 9.2, need to wait 5us minimum. Use a delay of 100us to 00CC13 1 ; cover accelerated Apples up to 20 MHz. 00CC13 1 ; 00CC13 1 A9 04 lda #WAIT_100us 00CC15 1 20 77 CD jsr Wait 00CC18 1 00CC18 1 A9 02 lda #$02 ; SRST=0, Disable INTRQ=1 00CC1A 1 9D 86 C0 sta ATADevCtrl,x 00CC1D 1 ; 00CC1D 1 ; Per ATA-6 sec 9.2, need to wait 2ms minimum. Use a delay of 40ms to 00CC1D 1 ; cover accelerated Apples up to 20 MHz. 00CC1D 1 ; 00CC1D 1 A9 7C lda #WAIT_40ms 00CC1F 1 20 77 CD jsr Wait 00CC22 1 00CC22 1 @skipBusReset: 00CC22 1 20 30 CC jsr DetermineDevPartitionCounts 00CC25 1 00CC25 1 ; Set the init done flag so init only happens once. 00CC25 1 @totalMaxPartitionsZero: 00CC25 1 A9 A5 lda #INIT_DONE_SIG 00CC27 1 99 78 04 sta DriveResetDone,Y 00CC2A 1 00CC2A 1 noNeedToResetBus: 00CC2A 1 A9 00 lda #0 00CC2C 1 99 78 07 sta DrvMiscFlags,Y 00CC2F 1 60 rts 00CC30 1 00CC30 1 00CC30 1 ;------------------------------------------------------------------------------ 00CC30 1 ; DetermineDevPartitionCounts 00CC30 1 ; 00CC30 1 ; For each device that has a MaxPartitions > 0 and is actually present, 00CC30 1 ; find out how many partitions it contains (up to its configured max). 00CC30 1 ; 00CC30 1 ; Inputs: 00CC30 1 ; X = slot * 16 00CC30 1 ; Y = slot 00CC30 1 ; PartitionsDev0,y = Max32MBPartitionsDev0 00CC30 1 ; PartitionsDev1,y = Max32MBPartitionsDev1 00CC30 1 ; 00CC30 1 ; Outputs: 00CC30 1 ; PartitionsDev0,y 00CC30 1 ; PartitionsDev1,y 00CC30 1 ;------------------------------------------------------------------------------ 00CC30 1 DetermineDevPartitionCounts: 00CC30 1 BD 82 C0 lda ClearCSMask,x ; reset MASK bit in PLD for normal CS0 signaling 00CC33 1 00CC33 1 20 66 CC jsr WaitForBusReadyAfterReset 00CC36 1 90 09 bcc @busReady 00CC38 1 00CC38 1 A9 00 lda #0 00CC3A 1 99 78 06 sta PartitionsDev0,y 00CC3D 1 99 F8 06 sta PartitionsDev1,y 00CC40 1 60 rts 00CC41 1 00CC41 1 @busReady: 00CC41 1 B9 78 06 lda PartitionsDev0,y 00CC44 1 F0 0D beq @skipDev0 00CC46 1 A9 E0 lda #$E0 ; $E0 = [1, LBA=1, 1, Drive=0, LBA 27-24] 00CC48 1 20 84 CC jsr CheckOneDevice_GetPartitionCount 00CC4B 1 D9 78 06 cmp PartitionsDev0,y 00CC4E 1 B0 03 bcs @skipDev0 ; don't increase beyond the configured number 00CC50 1 99 78 06 sta PartitionsDev0,y 00CC53 1 @skipDev0: 00CC53 1 00CC53 1 B9 F8 06 lda PartitionsDev1,y 00CC56 1 F0 0D beq @skipDev1 00CC58 1 A9 F0 lda #$F0 ; $F0 = [1, LBA=1, 1, Drive=1, LBA 27-24] 00CC5A 1 20 84 CC jsr CheckOneDevice_GetPartitionCount 00CC5D 1 D9 F8 06 cmp PartitionsDev1,y 00CC60 1 B0 03 bcs @skipDev1 ; don't increase beyond the configured number 00CC62 1 99 F8 06 sta PartitionsDev1,y 00CC65 1 @skipDev1: 00CC65 1 60 rts 00CC66 1 00CC66 1 00CC66 1 ;------------------------------------------------------------------------------ 00CC66 1 ; WaitForBusReadyAfterReset 00CC66 1 ; 00CC66 1 ; Inputs: 00CC66 1 ; X = slot * 16 ($n0) 00CC66 1 ; Y = slot 00CC66 1 ; 00CC66 1 ; Output: 00CC66 1 ; CLC if the ATA bus is available 00CC66 1 ; SEC if the bus remained busy -- no devices present? 00CC66 1 ;------------------------------------------------------------------------------ 00CC66 1 WaitForBusReadyAfterReset: 00CC66 1 5A PHY_OR_TYA_PHA 00CC67 1 AC 0C C8 ldy BusResetSeconds 00CC6A 1 @check: 00CC6A 1 BD 8F C0 lda ATAStatus,x 00CC6D 1 10 12 bpl @ready 00CC6F 1 00CC6F 1 ; Wait1Second 00CC6F 1 A9 0A lda #10 00CC71 1 48 : pha 00CC72 1 A9 C5 lda #WAIT_100ms 00CC74 1 20 77 CD jsr Wait 00CC77 1 68 pla 00CC78 1 3A DEC_A_OR_SBC1 00CC79 1 D0 F6 bne :- 00CC7B 1 00CC7B 1 88 dey 00CC7C 1 D0 EC bne @check 00CC7E 1 38 sec 00CC7F 1 B0 01 bcs @exit 00CC81 1 @ready: 00CC81 1 18 clc 00CC82 1 @exit: 00CC82 1 7A PLY_OR_PLA_TAY 00CC83 1 60 rts 00CC84 1 00CC84 1 ;------------------------------------------------------------------------------ 00CC84 1 ; CheckOneDevice_GetPartitionCount 00CC84 1 ; 00CC84 1 ; Check to see if a device is attached to the interface. 00CC84 1 ; 00CC84 1 ; Input: 00CC84 1 ; X = slot * 16 ($n0) 00CC84 1 ; Y = slot 00CC84 1 ; A = value for ATAHead ($E0 for Dev0, $F0 for Dev1) 00CC84 1 ; 00CC84 1 ; Output: 00CC84 1 ; A = number of partitions on device 00CC84 1 ; 00CC84 1 ; Checks to see if the drive status register is readable and equal to $50 00CC84 1 ; If so, return with the Carry clear, otherwise return with the carry set. 00CC84 1 ; Waits up to 10sec on a standard 1 MHz Apple II for drive to become ready 00CC84 1 ; 00CC84 1 ; If we determine (by timing out) that the specified device is not present, 00CC84 1 ; we set ATAHead to the *other* device. 00CC84 1 ;------------------------------------------------------------------------------ 00CC84 1 CheckOneDevice_GetPartitionCount: 00CC84 1 9D 8E C0 sta ATAHead,x 00CC87 1 99 F8 05 sta TempScreenHole,y 00CC8A 1 5A PHY_OR_TYA_PHA 00CC8B 1 AC 0D C8 ldy CheckDeviceTenths 00CC8E 1 BD 8F C0 : lda ATAStatus,x 00CC91 1 29 D0 and #%11010000 00CC93 1 C9 50 cmp #%01010000 ; if BUSY=0 and RDY=1 and DSC=1 00CC95 1 F0 14 beq @found 00CC97 1 A9 C5 lda #WAIT_100ms 00CC99 1 20 77 CD jsr Wait ; Wait 100ms for device to be ready 00CC9C 1 88 dey 00CC9D 1 D0 EF bne :- 00CC9F 1 7A PLY_OR_PLA_TAY 00CCA0 1 ; We timed out - the specified device is not present, so select the other one. 00CCA0 1 B9 F8 05 lda TempScreenHole,y 00CCA3 1 49 10 eor #$10 00CCA5 1 9D 8E C0 sta ATAHead,x 00CCA8 1 00CCA8 1 A9 00 lda #0 00CCAA 1 60 rts 00CCAB 1 00CCAB 1 @found: 00CCAB 1 7A PLY_OR_PLA_TAY 00CCAC 1 BD 8E C0 lda ATAHead,x 00CCAF 1 29 10 and #$10 00CCB1 1 0A asl a 00CCB2 1 0A asl a 00CCB3 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be bit 6 for this code" 00CCB3 1 99 78 07 sta DrvMiscFlags,y 00CCB6 1 00CCB6 1 A5 08 lda blockCount+2 00CCB8 1 48 pha 00CCB9 1 A5 07 lda blockCount+1 00CCBB 1 48 pha 00CCBC 1 A5 06 lda blockCount 00CCBE 1 48 pha 00CCBF 1 00CCBF 1 20 10 CD jsr GetDeviceBlockCount 00CCC2 1 A9 00 lda #0 00CCC4 1 B0 0A bcs @exit 00CCC6 1 00CCC6 1 ; Round *up* to the next whole number of 32MB partitions. 00CCC6 1 ; Start with blockCount+2 (number of 32MB multiples), and 00CCC6 1 ; add one if the two lower bytes are anything but $0000. 00CCC6 1 A5 06 lda blockCount 00CCC8 1 05 07 ora blockCount+1 00CCCA 1 C9 01 cmp #1 ; SEC if any bits set in blockCount, blockCount+1 00CCCC 1 A5 08 lda blockCount+2 00CCCE 1 69 00 adc #0 00CCD0 1 00CCD0 1 @exit: 00CCD0 1 99 F8 05 sta TempScreenHole,y 00CCD3 1 00CCD3 1 68 pla 00CCD4 1 85 06 sta blockCount 00CCD6 1 68 pla 00CCD7 1 85 07 sta blockCount+1 00CCD9 1 68 pla 00CCDA 1 85 08 sta blockCount+2 00CCDC 1 00CCDC 1 B9 F8 05 lda TempScreenHole,y 00CCDF 1 60 rts 00CCE0 1 00CCE0 1 ;------------------------------------------------------------------------------ 00CCE0 1 ; IDEWaitReady - Waits for BUSY flag to clear, and returns DRQ bit status 00CCE0 1 ; 00CCE0 1 ; Input: 00CCE0 1 ; X = slot*16 ($n0) 00CCE0 1 ; Ouput: 00CCE0 1 ; BNE if DRQ is set 00CCE0 1 ; BEQ if DRQ is clear 00CCE0 1 ; (used to be: Carry flag = DRQ status bit) 00CCE0 1 ; 00CCE0 1 ; CPU Registers changed: A, P 00CCE0 1 ;------------------------------------------------------------------------------ 00CCE0 1 IDEWaitReady: 00CCE0 1 BD 8F C0 : lda ATAStatus,x 00CCE3 1 30 FB bmi :- ; Wait for BUSY (bit 7) to be zero 00CCE5 1 29 08 and #$08 00CCE7 1 60 rts 00CCE8 1 00CCE8 1 ;------------------------------------------------------------------------------ 00CCE8 1 ; WaitReady_IssueCommand_CheckErr 00CCE8 1 ; 00CCE8 1 ; Input: A = ATA command 00CCE8 1 ; X = slot*16 00CCE8 1 ;------------------------------------------------------------------------------ 00CCE8 1 WaitReady_IssueIdentify_CheckErr: 00CCE8 1 A9 EC lda #ATAIdentify 00CCEA 1 WaitReady_IssueCommand_CheckErr: 00CCEA 1 48 pha 00CCEB 1 BD 8F C0 : lda ATAStatus,x 00CCEE 1 30 FB bmi :- ; Wait for BUSY (bit 7) to be zero 00CCF0 1 9E 80 C0 STZ_OR_STA_ATADataHigh_X 00CCF3 1 68 pla 00CCF4 1 9D 8F C0 sta ATACommand,x ; Issue the read command to the drive 00CCF7 1 ; jmp IDEWaitReadyCheckErr 00CCF7 1 ; 00CCF7 1 ; v v v FALL INTO v v v 00CCF7 1 ;------------------------------------------------------------------------------ 00CCF7 1 ; IDEWaitReadyCheckErr 00CCF7 1 ; 00CCF7 1 ; Input: 00CCF7 1 ; X = slot * 16 00CCF7 1 ; 00CCF7 1 ; Output: 00CCF7 1 ; BEQ error (DRQ=0, ERR=1) 00CCF7 1 ; BNE noError 00CCF7 1 ;------------------------------------------------------------------------------ 00CCF7 1 IDEWaitReadyCheckErr: 00CCF7 1 BD 8F C0 : lda ATAStatus,x 00CCFA 1 30 FB bmi :- ; Wait for BUSY (bit 7) to be zero 00CCFC 1 29 09 and #$09 00CCFE 1 .IF USE_65C02 00CCFE 1 3A dec a ; if DRQ=0 and ERR=1 (A=$01) an error occured 00CCFF 1 .ELSE 00CCFF 1 cmp #$01 ; if DRQ=0 and ERR=1 an error occured 00CCFF 1 .ENDIF 00CCFF 1 60 rts 00CD00 1 00CD00 1 00CD00 1 ;------------------------------------------------------------------------------ 00CD00 1 ; WaitReady_SetATAHeadFromMiscDrvFlags 00CD00 1 ; 00CD00 1 ; Input: X = slot*16 ($n0) 00CD00 1 ; DrvMiscFlags,y has been set up 00CD00 1 ; 00CD00 1 ; Output: A = the value stored into the ATAHead register 00CD00 1 ;------------------------------------------------------------------------------ 00CD00 1 WaitReady_SetATAHeadFromMiscDrvFlags: 00CD00 1 20 E0 CC jsr IDEWaitReady 00CD03 1 B9 78 07 lda DrvMiscFlags,y 00CD06 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be $40 for the following code" 00CD06 1 4A lsr a 00CD07 1 4A lsr a 00CD08 1 29 10 and #$10 00CD0A 1 09 E0 ora #$E0 ; $E0 = [1, LBA=1, 1, Drive, LBA 27-24] 00CD0C 1 9D 8E C0 sta ATAHead,x 00CD0F 1 60 rts 00CD10 1 00CD10 1 ;------------------------------------------------------------------------------ 00CD10 1 ; GetDeviceBlockCount 00CD10 1 ; 00CD10 1 ; Inputs: 00CD10 1 ; DrvMiscFlags,y has been set up 00CD10 1 ; X = slot * 16 00CD10 1 ; Y = slot 00CD10 1 ; 00CD10 1 ; Output: 00CD10 1 ; CLC, blockCount (3 bytes) -- size from device minus BlockOffset 00CD10 1 ; (Caller must save/restore these locations) 00CD10 1 ; SEC if error 00CD10 1 ;------------------------------------------------------------------------------ 00CD10 1 GetDeviceBlockCount: 00CD10 1 20 00 CD jsr WaitReady_SetATAHeadFromMiscDrvFlags 00CD13 1 20 E8 CC jsr WaitReady_IssueIdentify_CheckErr 00CD16 1 D0 04 bne @ok 00CD18 1 A9 27 lda #PRODOS_IO_ERROR 00CD1A 1 38 sec 00CD1B 1 60 rts 00CD1C 1 00CD1C 1 @ok: 00CD1C 1 5A PHY_OR_TYA_PHA 00CD1D 1 A0 00 ldy #0 ; zero loop counter 00CD1F 1 @tossWord: 00CD1F 1 BD 88 C0 lda ATADataLow,x ; Read words 0 thru 56 but throw them away 00CD22 1 C8 iny 00CD23 1 C0 39 cpy #57 ; Number of the first word to keep 00CD25 1 D0 F8 bne @tossWord 00CD27 1 7A PLY_OR_PLA_TAY 00CD28 1 00CD28 1 B9 78 07 lda DrvMiscFlags,y 00CD2B 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be $40 for this test" 00CD2B 1 0A asl a 00CD2C 1 0A asl a 00CD2D 1 5A PHY_OR_TYA_PHA 00CD2E 1 A0 00 ldy #0 00CD30 1 90 02 bcc @dev0 00CD32 1 ASSERT BlockOffsetDev1>BlockOffsetDev0, "BlockOffsetDev1 must come after Dev0" 00CD32 1 A0 03 ldy #BlockOffsetDev1-BlockOffsetDev0 00CD34 1 @dev0: 00CD34 1 00CD34 1 38 sec 00CD35 1 BD 88 C0 lda ATADataLow,x ; Read the current capacity in sectors (LBA) 00CD38 1 F9 0F C8 sbc BlockOffsetDev0,y 00CD3B 1 85 06 sta blockCount 00CD3D 1 00CD3D 1 BD 80 C0 lda ATADataHigh,x 00CD40 1 F9 10 C8 sbc BlockOffsetDev0+1,y 00CD43 1 85 07 sta blockCount+1 00CD45 1 00CD45 1 BD 88 C0 lda ATADataLow,x 00CD48 1 F9 11 C8 sbc BlockOffsetDev0+2,y 00CD4B 1 85 08 sta blockCount+2 00CD4D 1 00CD4D 1 BD 80 C0 lda ATADataHigh,x 00CD50 1 E9 00 sbc #0 00CD52 1 F0 08 beq @lessThan8GB 00CD54 1 00CD54 1 A9 FF lda #$ff 00CD56 1 85 06 sta blockCount 00CD58 1 85 07 sta blockCount+1 00CD5A 1 85 08 sta blockCount+2 00CD5C 1 00CD5C 1 @lessThan8GB: 00CD5C 1 7A PLY_OR_PLA_TAY 00CD5D 1 00CD5D 1 @tossRemaining: 00CD5D 1 20 E0 CC jsr IDEWaitReady ; read the rest of the words, until command ends 00CD60 1 F0 05 beq @done 00CD62 1 BD 88 C0 lda ATADataLow,x 00CD65 1 80 F6 BRA_OR_JMP @tossRemaining 00CD67 1 @done: 00CD67 1 18 clc 00CD68 1 60 rts 00CD69 1 00CD69 1 00CD69 1 ;------------------------------------------------------------------------------ 00CD69 1 ; IsDeviceKnownToExist 00CD69 1 ; 00CD69 1 ; Input: 00CD69 1 ; DrvMiscFlags,y is set up 00CD69 1 ; Y = slot 00CD69 1 ; Output: 00CD69 1 ; BNE = device exists 00CD69 1 ; BEQ = device does not exist 00CD69 1 ;------------------------------------------------------------------------------ 00CD69 1 IsDeviceKnownToExist: 00CD69 1 B9 78 07 lda DrvMiscFlags,y 00CD6C 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be bit 6 for this ASL" 00CD6C 1 0A asl a 00CD6D 1 30 04 bmi @dev1 00CD6F 1 00CD6F 1 B9 78 06 lda PartitionsDev0,y 00CD72 1 60 rts 00CD73 1 00CD73 1 @dev1: 00CD73 1 B9 F8 06 lda PartitionsDev1,y 00CD76 1 60 rts 00CD77 1 00CD77 1 00CD77 1 ;------------------------------------------------------------------------------ 00CD77 1 ; Wait - Copy of Apple's wait routine. Can't use ROM based routine in case 00CD77 1 ; ROM is not active when we need it. 00CD77 1 ; 00CD77 1 ; Input: 00CD77 1 ; A = desired delay time, where Delay(us) = .5(5A^2 + 27A + 26) 00CD77 1 ; or more usefully: A = (Delay[in uS]/2.5 + 2.09)^.5 - 2.7 00CD77 1 ; 00CD77 1 ; CPU Registers changed: A, P 00CD77 1 ;------------------------------------------------------------------------------ 00CD77 1 Wait: 00CD77 1 38 sec 00CD78 1 @Wait2: 00CD78 1 48 pha 00CD79 1 @Wait3: 00CD79 1 E9 01 sbc #1 00CD7B 1 D0 FC bne @Wait3 00CD7D 1 68 pla 00CD7E 1 E9 01 sbc #1 00CD80 1 D0 F6 bne @Wait2 00CD82 1 60 rts 00CD83 1 00CD83 1 ;------------------------------------------------------------------------------ 00CD83 1 ; RemapAndStoreDriveNum 00CD83 1 ; 00CD83 1 ; Input: A = logical drive number (0 = first partition, 1 = second, ...) 00CD83 1 ; Y = slot 00CD83 1 ; DrvMiscFlags,Y does not have the kMiscDev1 bit set yet 00CD83 1 ; BootDevice,Y indicates which device's partitions come first 00CD83 1 ; BootPartition,Y indicates the boot partition (0=first) 00CD83 1 ; 00CD83 1 ; Output: SEC = error (no such partition) 00CD83 1 ; A = error code 00CD83 1 ; CLC = no error 00CD83 1 ; DriveNumber,Y = A = physical drive number 00CD83 1 ; DrvMiscFlags,Y --> set kMiscDev1 if Dev1 00CD83 1 ; X and Y are preserved 00CD83 1 ; 00CD83 1 ; Bring the desired partition to #0 by swapping it with the first one 00CD83 1 ; (for example, if you boot from partition #3 then eight 32MB chunks 00CD83 1 ; on the device appear will in the order: 3, 1, 2, 0, 4, 5, 6, 7). 00CD83 1 ; 00CD83 1 ; If you have two devices, all the partitions on the boot device come 00CD83 1 ; before all the partitions on the non-boot device. 00CD83 1 ; 00CD83 1 ; Algorithm: 00CD83 1 ; 00CD83 1 ; If BootDevice == Dev0: 00CD83 1 ; ; Dev0 comes first 00CD83 1 ; swap 0 with BootPartition 00CD83 1 ; If P >= NumPartitionsDev0: 00CD83 1 ; MiscFlags = Dev1 00CD83 1 ; P -= NumPartitionsDev0 00CD83 1 ; If P >= NumPartitionsDev1, error. 00CD83 1 ; Else 00CD83 1 ; ; Dev1 comes first 00CD83 1 ; swap 0 with BootPartition 00CD83 1 ; If P >= NumPartitionsDev1: 00CD83 1 ; P -= NumPartitionsDev1 00CD83 1 ; if P >= NumPartitionsDev0, error. 00CD83 1 ; else 00CD83 1 ; MiscFlags = Dev1 00CD83 1 ; 00CD83 1 ;------------------------------------------------------------------------------ 00CD83 1 RemapAndStoreDriveNum: 00CD83 1 48 pha 00CD84 1 B9 78 05 lda BootDevice,y 00CD87 1 D0 22 bne @dev1BeforeDev0 00CD89 1 00CD89 1 ; Dev0 partitions come first (the normal order) 00CD89 1 ; 00CD89 1 ; (1) Swap 0 with BootPartition 00CD89 1 ; 00CD89 1 ; (2) if P >= PartitionsDev0: 00CD89 1 ; MiscFlags = Dev1 00CD89 1 ; P -= PartitionsDev0 00CD89 1 ; if P >= PartitionsDev1, error. 00CD89 1 68 pla 00CD8A 1 F0 09 beq @swapToBootPartition 00CD8C 1 D9 F8 07 cmp BootPartition,y 00CD8F 1 D0 07 bne @haveAdjustedPartitionIndex 00CD91 1 @physicalZero: 00CD91 1 A9 00 lda #0 ; map the boot partition's "normal" location to physical 0 00CD93 1 F0 03 beq @haveAdjustedPartitionIndex 00CD95 1 @swapToBootPartition: 00CD95 1 B9 F8 07 lda BootPartition,y ; map 0 to physical location of boot partition 00CD98 1 @haveAdjustedPartitionIndex: 00CD98 1 99 F8 04 sta DriveNumber,y 00CD9B 1 38 sec 00CD9C 1 F9 78 06 sbc PartitionsDev0,y ; SBC affects Carry just like CMP 00CD9F 1 90 32 bcc @noError 00CDA1 1 99 F8 04 sta DriveNumber,y 00CDA4 1 D9 F8 06 cmp PartitionsDev1,y 00CDA7 1 B0 22 bcs @tooLarge 00CDA9 1 90 23 bcc @onDev1 00CDAB 1 00CDAB 1 ; Dev1 partitions come first 00CDAB 1 ; 00CDAB 1 ; (1) Swap 0 with BootPartition 00CDAB 1 ; 00CDAB 1 ; (2) if P >= PartitionsDev1: 00CDAB 1 ; P -= PartitionsDev1 00CDAB 1 ; if P >= PartitionsDev0, error. 00CDAB 1 ; else 00CDAB 1 ; MiscFlags = Dev1 00CDAB 1 @dev1BeforeDev0: 00CDAB 1 68 pla 00CDAC 1 F0 09 beq @swapToBootPartitionDev1 00CDAE 1 D9 F8 07 cmp BootPartition,y 00CDB1 1 D0 07 bne @haveAdjustedPartitionIndexDev1 00CDB3 1 @physicalZeroDev1: 00CDB3 1 A9 00 lda #0 00CDB5 1 F0 03 beq @haveAdjustedPartitionIndexDev1 00CDB7 1 @swapToBootPartitionDev1: 00CDB7 1 B9 F8 07 lda BootPartition,y 00CDBA 1 @haveAdjustedPartitionIndexDev1: 00CDBA 1 99 F8 04 sta DriveNumber,y 00CDBD 1 38 sec 00CDBE 1 F9 F8 06 sbc PartitionsDev1,y ; SBC affects Carry just like CMP 00CDC1 1 90 0B bcc @onDev1 00CDC3 1 99 F8 04 sta DriveNumber,y 00CDC6 1 D9 78 06 cmp PartitionsDev0,y 00CDC9 1 90 08 bcc @noError 00CDCB 1 @tooLarge: ; carry is already set 00CDCB 1 A9 28 lda #PRODOS_NO_DEVICE 00CDCD 1 ; sec 00CDCD 1 60 rts 00CDCE 1 00CDCE 1 @onDev1: ; carry is already clear 00CDCE 1 A9 40 lda #kMiscDev1 00CDD0 1 ; ora DrvMiscFlags,y 00CDD0 1 99 78 07 sta DrvMiscFlags,y 00CDD3 1 @noError: 00CDD3 1 ; clc 00CDD3 1 B9 F8 04 lda DriveNumber,y 00CDD6 1 60 rts 00CDD7 1 00CDD7 1 ;============================================================================== 00CDD7 1 ;============================================================================== 00CDD7 1 00CDD7 1 .IF FULL_MENU=0 00CDD7 1 ;------------------------------------------------------------------------------ 00CDD7 1 ; InteractiveMenu for 6502 00CDD7 1 ; 00CDD7 1 ; INPUT: X = slot*16, Y = slot 00CDD7 1 ; 00CDD7 1 ; RTS to caller to continue booting. 00CDD7 1 ;------------------------------------------------------------------------------ 00CDD7 1 InteractiveMenu_Impl: 00CDD7 1 rts 00CDD7 1 .ELSE 00CDD7 1 ;------------------------------------------------------------------------------ 00CDD7 1 ; InteractiveMenu_Impl 00CDD7 1 ; 00CDD7 1 ; INPUT: X = slot*16, Y = slot 00CDD7 1 ; 00CDD7 1 ; RTS to caller to continue booting. 00CDD7 1 ;------------------------------------------------------------------------------ 00CDD7 1 kMenuInteractiveRows = 4 00CDD7 1 kMenuTotalRows = 5 00CDD7 1 00CDD7 1 kRowPartitionsDev0 = 0 00CDD7 1 kRowPartitionsDev1 = 1 00CDD7 1 kRowBootDevice = 2 00CDD7 1 kRowBootPartition = 3 00CDD7 1 kRowBootSaveQuit = 4 00CDD7 1 00CDD7 1 ASSERT (Max32MBPartitionsDev0-Max32MBPartitionsDev0)=kRowPartitionsDev0, "oops" 00CDD7 1 ASSERT (Max32MBPartitionsDev1-Max32MBPartitionsDev0)=kRowPartitionsDev1, "oops" 00CDD7 1 ASSERT (DefaultBootDevice-Max32MBPartitionsDev0)=kRowBootDevice, "oops" 00CDD7 1 ASSERT (DefaultBootPartition-Max32MBPartitionsDev0)=kRowBootPartition, "oops" 00CDD7 1 00CDD7 1 kMenuTop = 10 00CDD7 1 kMenuBootSaveQuitLine = 21 00CDD7 1 00CDD7 1 kMenuAlignment = 20 00CDD7 1 00CDD7 1 menuVTAB: 00CDD7 1 0A .byte kMenuTop 00CDD8 1 0B .byte kMenuTop+1 00CDD9 1 0D .byte kMenuTop+3 00CDDA 1 0E .byte kMenuTop+4 00CDDB 1 15 .byte kMenuBootSaveQuitLine 00CDDC 1 menuHTAB: 00CDDC 1 03 .byte kMenuAlignment-15-2 00CDDD 1 0E .byte kMenuAlignment-4-2 00CDDE 1 0A .byte kMenuAlignment-8-2 00CDDF 1 09 .byte kMenuAlignment-9-2 00CDE0 1 08 .byte 8 00CDE1 1 menuRowText: 00CDE1 1 19 .byte MsgMenuRow0-Messages 00CDE2 1 28 .byte MsgMenuRow1-Messages 00CDE3 1 2C .byte MsgMenuRow2-Messages 00CDE4 1 34 .byte MsgMenuRow3-Messages 00CDE5 1 3D .byte MsgBootSaveQuit-Messages 00CDE6 1 menuMinimumValues: 00CDE6 1 00 00 00 01 .byte 0, 0, 0, 1 00CDEA 1 menuMaximumValuesPlusOne: 00CDEA 1 0E 0E 02 0E .byte 13+1, 13+1, 1+1, 13+1 00CDEE 1 00CDEE 1 00CDEE 1 InteractiveMenu_Impl: 00CDEE 1 86 41 stx menuSlot16 00CDF0 1 84 40 sty menuSlot 00CDF2 1 ; Intentionally change $01 so that monitor SLOOP won't continue the boot scan. 00CDF2 1 84 01 sty $01 ; store anything *other* than $Cn 00CDF4 1 00CDF4 1 ; Reset goes to BASIC 00CDF4 1 .if USE_65C02 00CDF4 1 9C F2 03 stz ResetVector 00CDF7 1 .else 00CDF7 1 lda #