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 .byte "65C02" 00C050 1 .ELSE 00C050 1 36 35 30 32 .byte "6502" 00C054 1 .ENDIF 00C054 1 20 6F 72 20 .byte " or later.",CR,CR 00C058 1 6C 61 74 65 00C05C 1 72 2E 0D 0D 00C060 1 .IF REQUIRES_EEPROM 00C060 1 52 65 71 75 .byte "Requires CFFA with EEPROM, not EPROM.",CR,CR 00C064 1 69 72 65 73 00C068 1 20 43 46 46 00C087 1 .ELSE 00C087 1 .byte "Compatible with older EPROM-based CFFA cards.",CR,CR 00C087 1 .ENDIF 00C087 1 FF FF FF FF .RES $C100-*, $FF ; fill the rest of the $C0xx area (unused) 00C08B 1 FF FF FF FF 00C08F 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 00CBA9 1 AA tax 00CBAA 1 00CBAA 1 68 pla 00CBAB 1 85 EF sta zpt1 00CBAD 1 68 pla 00CBAE 1 85 45 sta pdIOBufferH 00CBB0 1 00CBB0 1 68 pla 00CBB1 1 85 46 sta pdBlockNumber 00CBB3 1 68 pla 00CBB4 1 85 47 sta pdBlockNumberH 00CBB6 1 00CBB6 1 8A txa 00CBB7 1 60 rts 00CBB8 1 00CBB8 1 @PLP_ioError: 00CBB8 1 28 plp 00CBB9 1 @ioError: 00CBB9 1 A9 27 lda #PRODOS_IO_ERROR 00CBBB 1 D0 EA bne @outErrorA 00CBBD 1 00CBBD 1 ;------------------------------------------------------------------------------ 00CBBD 1 ; Block2LBA - Translates ProDOS block# into LBA and programs device's task file 00CBBD 1 ; registers. 00CBBD 1 ; 00CBBD 1 ; Input: 00CBBD 1 ; pd Command Block Data $42 - $47 00CBBD 1 ; DrvMiscFlags,y has been set up to specify Dev0 or Dev1 00CBBD 1 ; DriveNumber,y specifies a 32MB chunk (physical partition number) 00CBBD 1 ; X = slot * 16 ($n0) 00CBBD 1 ; Y = slot 00CBBD 1 ; 00CBBD 1 ; Ouput: 00CBBD 1 ; None 00CBBD 1 ; 00CBBD 1 ; ZeroPage Usage: 00CBBD 1 ; None 00CBBD 1 ; 00CBBD 1 ; CPU Registers changed: A, P 00CBBD 1 ; 00CBBD 1 ; This function translates the block number sent in the ProDOS request 00CBBD 1 ; packet, into an ATA Logical Block Address (LBA). 00CBBD 1 ; The least significant 16 bits becomes the ProDOS block#. 00CBBD 1 ; The most significant 16 becomes the ProDOS Drive # 00CBBD 1 ; 00CBBD 1 ; A ProDOS block and a ATA sector are both 512 bytes. 00CBBD 1 ; 00CBBD 1 ; Logical Block Mode, the Logical Block Address is interpreted as follows: 00CBBD 1 ; LBA07-LBA00: Sector Number Register D7-D0. 00CBBD 1 ; LBA15-LBA08: Cylinder Low Register D7-D0. 00CBBD 1 ; LBA23-LBA16: Cylinder High Register D7-D0. 00CBBD 1 ; LBA27-LBA24: Drive/Head Register bits HS3-HS0. 00CBBD 1 ;------------------------------------------------------------------------------ 00CBBD 1 Block2LBA: 00CBBD 1 20 2B CD jsr WaitReady_SetATAHeadFromMiscDrvFlags 00CBC0 1 00CBC0 1 A9 01 lda #1 00CBC2 1 9D 8A C0 sta ATASectorCnt,x 00CBC5 1 ; 00CBC5 1 ; Add BlockOffset to the ProDOS block number to offset the first drive block we 00CBC5 1 ; use. This keeps the device's first BlockOffset blocks free, which usually 00CBC5 1 ; includes a MBR at block 0. 00CBC5 1 ; 00CBC5 1 B9 78 07 lda DrvMiscFlags,y ; bit 7 = raw block access 00CBC8 1 ASSERT kMiscRaw=$80, "kMiscRaw must be $80 so we can test it with BMI" 00CBC8 1 .if SMARTPORT_RAW_BLOCK_MAGIC 00CBC8 1 bmi @rawBlocks 00CBC8 1 .endif 00CBC8 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be $40 for this test" 00CBC8 1 0A asl a ; since A<$80, this clears the carry 00CBC9 1 30 1A bmi @dev1 00CBCB 1 00CBCB 1 ; clc 00CBCB 1 A5 46 lda pdBlockNumber 00CBCD 1 6D 0F C8 adc BlockOffsetDev0 00CBD0 1 9D 8B C0 sta ATASector,x ; store ProDOS Low block # into LBA 0-7 00CBD3 1 00CBD3 1 A5 47 lda pdBlockNumberH 00CBD5 1 6D 10 C8 adc BlockOffsetDev0+1 00CBD8 1 9D 8C C0 sta ATACylinder,x ; store ProDOS High block # into LBA 15-8 00CBDB 1 00CBDB 1 AD 11 C8 lda BlockOffsetDev0+2 00CBDE 1 @addDriveAndStoreCylinderH: 00CBDE 1 79 F8 04 adc DriveNumber,y 00CBE1 1 9D 8D C0 sta ATACylinderH,x ; store LBA bits 23-16 00CBE4 1 60 rts 00CBE5 1 00CBE5 1 @dev1: 00CBE5 1 ; clc 00CBE5 1 A5 46 lda pdBlockNumber 00CBE7 1 6D 12 C8 adc BlockOffsetDev1 00CBEA 1 9D 8B C0 sta ATASector,x ; store ProDOS Low block # into LBA 0-7 00CBED 1 00CBED 1 A5 47 lda pdBlockNumberH 00CBEF 1 6D 13 C8 adc BlockOffsetDev1+1 00CBF2 1 9D 8C C0 sta ATACylinder,x ; store ProDOS High block # into LBA 15-8 00CBF5 1 00CBF5 1 AD 14 C8 lda BlockOffsetDev1+2 00CBF8 1 4C DE CB BRA_OR_JMP @addDriveAndStoreCylinderH 00CBFB 1 00CBFB 1 .if SMARTPORT_RAW_BLOCK_MAGIC 00CBFB 1 @rawBlocks: 00CBFB 1 lda pdBlockNumber 00CBFB 1 sta ATASector,x ; store ProDOS Low block # into LBA 0-7 00CBFB 1 lda pdBlockNumberH 00CBFB 1 sta ATACylinder,x ; store ProDOS High block # into LBA 15-8 00CBFB 1 lda DriveNumber,y 00CBFB 1 BRA_OR_JMP @storeCylinderH 00CBFB 1 .endif 00CBFB 1 00CBFB 1 ;------------------------------------------------------------------------------ 00CBFB 1 ; ResetBusIfFirstTime_ClearMiscFlags 00CBFB 1 ; 00CBFB 1 ; Reset the bus (both devices) once, the first time the driver is called. 00CBFB 1 ; 00CBFB 1 ; ide_devctrl Bit 2 = Software Reset, Bit 1 = nIEN (enable assertion of INTRQ) 00CBFB 1 ; 00CBFB 1 ; Input: 00CBFB 1 ; X = slot * 16 ($n0) 00CBFB 1 ; Y = slot 00CBFB 1 ; 00CBFB 1 ; ZeroPage Usage: 00CBFB 1 ; None 00CBFB 1 ; 00CBFB 1 ; CPU Registers changed: A, P 00CBFB 1 ;------------------------------------------------------------------------------ 00CBFB 1 INIT_DONE_SIG = $A5 00CBFB 1 00CBFB 1 ResetBusIfFirstTime_ClearMiscFlags: 00CBFB 1 B9 78 04 lda DriveResetDone,Y 00CBFE 1 C9 A5 cmp #INIT_DONE_SIG 00CC00 1 F0 49 beq noNeedToResetBus 00CC02 1 00CC02 1 ResetBusAlways_ClearMiscFlags: 00CC02 1 AD 03 C8 lda DefaultBootPartition 00CC05 1 38 E9 01 DEC_A_OR_SBC1 00CC08 1 99 F8 07 sta BootPartition,y 00CC0B 1 AD 02 C8 lda DefaultBootDevice 00CC0E 1 99 78 05 sta BootDevice,y 00CC11 1 00CC11 1 AD 00 C8 lda Max32MBPartitionsDev0 00CC14 1 99 78 06 sta PartitionsDev0,y 00CC17 1 AD 01 C8 lda Max32MBPartitionsDev1 00CC1A 1 99 F8 06 sta PartitionsDev1,y 00CC1D 1 19 78 06 ora PartitionsDev0,y 00CC20 1 F0 24 beq @totalMaxPartitionsZero 00CC22 1 ; 00CC22 1 ; Reset the ATA bus (applies to both devices at once) 00CC22 1 ; 00CC22 1 BD 82 C0 lda ClearCSMask,x ; reset MASK bit in PLD for normal CS0 signaling 00CC25 1 00CC25 1 A9 00 9D 80 STZ_OR_STA_ATADataHigh_X 00CC29 1 C0 00CC2A 1 00CC2A 1 AD 0E C8 lda ConfigOptionBits 00CC2D 1 30 14 bmi @skipBusReset 00CC2F 1 00CC2F 1 A9 06 lda #$06 ; SRST (software reset) = 1, Disable INTRQ=1 00CC31 1 9D 86 C0 sta ATADevCtrl,x 00CC34 1 ; 00CC34 1 ; Per ATA-6 sec 9.2, need to wait 5us minimum. Use a delay of 100us to 00CC34 1 ; cover accelerated Apples up to 20 MHz. 00CC34 1 ; 00CC34 1 A9 04 lda #WAIT_100us 00CC36 1 20 A7 CD jsr Wait 00CC39 1 00CC39 1 A9 02 lda #$02 ; SRST=0, Disable INTRQ=1 00CC3B 1 9D 86 C0 sta ATADevCtrl,x 00CC3E 1 ; 00CC3E 1 ; Per ATA-6 sec 9.2, need to wait 2ms minimum. Use a delay of 40ms to 00CC3E 1 ; cover accelerated Apples up to 20 MHz. 00CC3E 1 ; 00CC3E 1 A9 7C lda #WAIT_40ms 00CC40 1 20 A7 CD jsr Wait 00CC43 1 00CC43 1 @skipBusReset: 00CC43 1 20 51 CC jsr DetermineDevPartitionCounts 00CC46 1 00CC46 1 ; Set the init done flag so init only happens once. 00CC46 1 @totalMaxPartitionsZero: 00CC46 1 A9 A5 lda #INIT_DONE_SIG 00CC48 1 99 78 04 sta DriveResetDone,Y 00CC4B 1 00CC4B 1 noNeedToResetBus: 00CC4B 1 A9 00 lda #0 00CC4D 1 99 78 07 sta DrvMiscFlags,Y 00CC50 1 60 rts 00CC51 1 00CC51 1 00CC51 1 ;------------------------------------------------------------------------------ 00CC51 1 ; DetermineDevPartitionCounts 00CC51 1 ; 00CC51 1 ; For each device that has a MaxPartitions > 0 and is actually present, 00CC51 1 ; find out how many partitions it contains (up to its configured max). 00CC51 1 ; 00CC51 1 ; Inputs: 00CC51 1 ; X = slot * 16 00CC51 1 ; Y = slot 00CC51 1 ; PartitionsDev0,y = Max32MBPartitionsDev0 00CC51 1 ; PartitionsDev1,y = Max32MBPartitionsDev1 00CC51 1 ; 00CC51 1 ; Outputs: 00CC51 1 ; PartitionsDev0,y 00CC51 1 ; PartitionsDev1,y 00CC51 1 ;------------------------------------------------------------------------------ 00CC51 1 DetermineDevPartitionCounts: 00CC51 1 BD 82 C0 lda ClearCSMask,x ; reset MASK bit in PLD for normal CS0 signaling 00CC54 1 00CC54 1 20 87 CC jsr WaitForBusReadyAfterReset 00CC57 1 90 09 bcc @busReady 00CC59 1 00CC59 1 A9 00 lda #0 00CC5B 1 99 78 06 sta PartitionsDev0,y 00CC5E 1 99 F8 06 sta PartitionsDev1,y 00CC61 1 60 rts 00CC62 1 00CC62 1 @busReady: 00CC62 1 B9 78 06 lda PartitionsDev0,y 00CC65 1 F0 0D beq @skipDev0 00CC67 1 A9 E0 lda #$E0 ; $E0 = [1, LBA=1, 1, Drive=0, LBA 27-24] 00CC69 1 20 A9 CC jsr CheckOneDevice_GetPartitionCount 00CC6C 1 D9 78 06 cmp PartitionsDev0,y 00CC6F 1 B0 03 bcs @skipDev0 ; don't increase beyond the configured number 00CC71 1 99 78 06 sta PartitionsDev0,y 00CC74 1 @skipDev0: 00CC74 1 00CC74 1 B9 F8 06 lda PartitionsDev1,y 00CC77 1 F0 0D beq @skipDev1 00CC79 1 A9 F0 lda #$F0 ; $F0 = [1, LBA=1, 1, Drive=1, LBA 27-24] 00CC7B 1 20 A9 CC jsr CheckOneDevice_GetPartitionCount 00CC7E 1 D9 F8 06 cmp PartitionsDev1,y 00CC81 1 B0 03 bcs @skipDev1 ; don't increase beyond the configured number 00CC83 1 99 F8 06 sta PartitionsDev1,y 00CC86 1 @skipDev1: 00CC86 1 60 rts 00CC87 1 00CC87 1 00CC87 1 ;------------------------------------------------------------------------------ 00CC87 1 ; WaitForBusReadyAfterReset 00CC87 1 ; 00CC87 1 ; Inputs: 00CC87 1 ; X = slot * 16 ($n0) 00CC87 1 ; Y = slot 00CC87 1 ; 00CC87 1 ; Output: 00CC87 1 ; CLC if the ATA bus is available 00CC87 1 ; SEC if the bus remained busy -- no devices present? 00CC87 1 ;------------------------------------------------------------------------------ 00CC87 1 WaitForBusReadyAfterReset: 00CC87 1 98 48 PHY_OR_TYA_PHA 00CC89 1 AC 0C C8 ldy BusResetSeconds 00CC8C 1 @check: 00CC8C 1 BD 8F C0 lda ATAStatus,x 00CC8F 1 10 14 bpl @ready 00CC91 1 00CC91 1 ; Wait1Second 00CC91 1 A9 0A lda #10 00CC93 1 48 : pha 00CC94 1 A9 C5 lda #WAIT_100ms 00CC96 1 20 A7 CD jsr Wait 00CC99 1 68 pla 00CC9A 1 38 E9 01 DEC_A_OR_SBC1 00CC9D 1 D0 F4 bne :- 00CC9F 1 00CC9F 1 88 dey 00CCA0 1 D0 EA bne @check 00CCA2 1 38 sec 00CCA3 1 B0 01 bcs @exit 00CCA5 1 @ready: 00CCA5 1 18 clc 00CCA6 1 @exit: 00CCA6 1 68 A8 PLY_OR_PLA_TAY 00CCA8 1 60 rts 00CCA9 1 00CCA9 1 ;------------------------------------------------------------------------------ 00CCA9 1 ; CheckOneDevice_GetPartitionCount 00CCA9 1 ; 00CCA9 1 ; Check to see if a device is attached to the interface. 00CCA9 1 ; 00CCA9 1 ; Input: 00CCA9 1 ; X = slot * 16 ($n0) 00CCA9 1 ; Y = slot 00CCA9 1 ; A = value for ATAHead ($E0 for Dev0, $F0 for Dev1) 00CCA9 1 ; 00CCA9 1 ; Output: 00CCA9 1 ; A = number of partitions on device 00CCA9 1 ; 00CCA9 1 ; Checks to see if the drive status register is readable and equal to $50 00CCA9 1 ; If so, return with the Carry clear, otherwise return with the carry set. 00CCA9 1 ; Waits up to 10sec on a standard 1 MHz Apple II for drive to become ready 00CCA9 1 ; 00CCA9 1 ; If we determine (by timing out) that the specified device is not present, 00CCA9 1 ; we set ATAHead to the *other* device. 00CCA9 1 ;------------------------------------------------------------------------------ 00CCA9 1 CheckOneDevice_GetPartitionCount: 00CCA9 1 9D 8E C0 sta ATAHead,x 00CCAC 1 99 F8 05 sta TempScreenHole,y 00CCAF 1 98 48 PHY_OR_TYA_PHA 00CCB1 1 AC 0D C8 ldy CheckDeviceTenths 00CCB4 1 BD 8F C0 : lda ATAStatus,x 00CCB7 1 29 D0 and #%11010000 00CCB9 1 C9 50 cmp #%01010000 ; if BUSY=0 and RDY=1 and DSC=1 00CCBB 1 F0 15 beq @found 00CCBD 1 A9 C5 lda #WAIT_100ms 00CCBF 1 20 A7 CD jsr Wait ; Wait 100ms for device to be ready 00CCC2 1 88 dey 00CCC3 1 D0 EF bne :- 00CCC5 1 68 A8 PLY_OR_PLA_TAY 00CCC7 1 ; We timed out - the specified device is not present, so select the other one. 00CCC7 1 B9 F8 05 lda TempScreenHole,y 00CCCA 1 49 10 eor #$10 00CCCC 1 9D 8E C0 sta ATAHead,x 00CCCF 1 00CCCF 1 A9 00 lda #0 00CCD1 1 60 rts 00CCD2 1 00CCD2 1 @found: 00CCD2 1 68 A8 PLY_OR_PLA_TAY 00CCD4 1 BD 8E C0 lda ATAHead,x 00CCD7 1 29 10 and #$10 00CCD9 1 0A asl a 00CCDA 1 0A asl a 00CCDB 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be bit 6 for this code" 00CCDB 1 99 78 07 sta DrvMiscFlags,y 00CCDE 1 00CCDE 1 A5 08 lda blockCount+2 00CCE0 1 48 pha 00CCE1 1 A5 07 lda blockCount+1 00CCE3 1 48 pha 00CCE4 1 A5 06 lda blockCount 00CCE6 1 48 pha 00CCE7 1 00CCE7 1 20 3B CD jsr GetDeviceBlockCount 00CCEA 1 A9 00 lda #0 00CCEC 1 B0 0A bcs @exit 00CCEE 1 00CCEE 1 ; Round *up* to the next whole number of 32MB partitions. 00CCEE 1 ; Start with blockCount+2 (number of 32MB multiples), and 00CCEE 1 ; add one if the two lower bytes are anything but $0000. 00CCEE 1 A5 06 lda blockCount 00CCF0 1 05 07 ora blockCount+1 00CCF2 1 C9 01 cmp #1 ; SEC if any bits set in blockCount, blockCount+1 00CCF4 1 A5 08 lda blockCount+2 00CCF6 1 69 00 adc #0 00CCF8 1 00CCF8 1 @exit: 00CCF8 1 99 F8 05 sta TempScreenHole,y 00CCFB 1 00CCFB 1 68 pla 00CCFC 1 85 06 sta blockCount 00CCFE 1 68 pla 00CCFF 1 85 07 sta blockCount+1 00CD01 1 68 pla 00CD02 1 85 08 sta blockCount+2 00CD04 1 00CD04 1 B9 F8 05 lda TempScreenHole,y 00CD07 1 60 rts 00CD08 1 00CD08 1 ;------------------------------------------------------------------------------ 00CD08 1 ; IDEWaitReady - Waits for BUSY flag to clear, and returns DRQ bit status 00CD08 1 ; 00CD08 1 ; Input: 00CD08 1 ; X = slot*16 ($n0) 00CD08 1 ; Ouput: 00CD08 1 ; BNE if DRQ is set 00CD08 1 ; BEQ if DRQ is clear 00CD08 1 ; (used to be: Carry flag = DRQ status bit) 00CD08 1 ; 00CD08 1 ; CPU Registers changed: A, P 00CD08 1 ;------------------------------------------------------------------------------ 00CD08 1 IDEWaitReady: 00CD08 1 BD 8F C0 : lda ATAStatus,x 00CD0B 1 30 FB bmi :- ; Wait for BUSY (bit 7) to be zero 00CD0D 1 29 08 and #$08 00CD0F 1 60 rts 00CD10 1 00CD10 1 ;------------------------------------------------------------------------------ 00CD10 1 ; WaitReady_IssueCommand_CheckErr 00CD10 1 ; 00CD10 1 ; Input: A = ATA command 00CD10 1 ; X = slot*16 00CD10 1 ;------------------------------------------------------------------------------ 00CD10 1 WaitReady_IssueIdentify_CheckErr: 00CD10 1 A9 EC lda #ATAIdentify 00CD12 1 WaitReady_IssueCommand_CheckErr: 00CD12 1 48 pha 00CD13 1 BD 8F C0 : lda ATAStatus,x 00CD16 1 30 FB bmi :- ; Wait for BUSY (bit 7) to be zero 00CD18 1 A9 00 9D 80 STZ_OR_STA_ATADataHigh_X 00CD1C 1 C0 00CD1D 1 68 pla 00CD1E 1 9D 8F C0 sta ATACommand,x ; Issue the read command to the drive 00CD21 1 ; jmp IDEWaitReadyCheckErr 00CD21 1 ; 00CD21 1 ; v v v FALL INTO v v v 00CD21 1 ;------------------------------------------------------------------------------ 00CD21 1 ; IDEWaitReadyCheckErr 00CD21 1 ; 00CD21 1 ; Input: 00CD21 1 ; X = slot * 16 00CD21 1 ; 00CD21 1 ; Output: 00CD21 1 ; BEQ error (DRQ=0, ERR=1) 00CD21 1 ; BNE noError 00CD21 1 ;------------------------------------------------------------------------------ 00CD21 1 IDEWaitReadyCheckErr: 00CD21 1 BD 8F C0 : lda ATAStatus,x 00CD24 1 30 FB bmi :- ; Wait for BUSY (bit 7) to be zero 00CD26 1 29 09 and #$09 00CD28 1 .IF USE_65C02 00CD28 1 dec a ; if DRQ=0 and ERR=1 (A=$01) an error occured 00CD28 1 .ELSE 00CD28 1 C9 01 cmp #$01 ; if DRQ=0 and ERR=1 an error occured 00CD2A 1 .ENDIF 00CD2A 1 60 rts 00CD2B 1 00CD2B 1 00CD2B 1 ;------------------------------------------------------------------------------ 00CD2B 1 ; WaitReady_SetATAHeadFromMiscDrvFlags 00CD2B 1 ; 00CD2B 1 ; Input: X = slot*16 ($n0) 00CD2B 1 ; DrvMiscFlags,y has been set up 00CD2B 1 ; 00CD2B 1 ; Output: A = the value stored into the ATAHead register 00CD2B 1 ;------------------------------------------------------------------------------ 00CD2B 1 WaitReady_SetATAHeadFromMiscDrvFlags: 00CD2B 1 20 08 CD jsr IDEWaitReady 00CD2E 1 B9 78 07 lda DrvMiscFlags,y 00CD31 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be $40 for the following code" 00CD31 1 4A lsr a 00CD32 1 4A lsr a 00CD33 1 29 10 and #$10 00CD35 1 09 E0 ora #$E0 ; $E0 = [1, LBA=1, 1, Drive, LBA 27-24] 00CD37 1 9D 8E C0 sta ATAHead,x 00CD3A 1 60 rts 00CD3B 1 00CD3B 1 ;------------------------------------------------------------------------------ 00CD3B 1 ; GetDeviceBlockCount 00CD3B 1 ; 00CD3B 1 ; Inputs: 00CD3B 1 ; DrvMiscFlags,y has been set up 00CD3B 1 ; X = slot * 16 00CD3B 1 ; Y = slot 00CD3B 1 ; 00CD3B 1 ; Output: 00CD3B 1 ; CLC, blockCount (3 bytes) -- size from device minus BlockOffset 00CD3B 1 ; (Caller must save/restore these locations) 00CD3B 1 ; SEC if error 00CD3B 1 ;------------------------------------------------------------------------------ 00CD3B 1 GetDeviceBlockCount: 00CD3B 1 20 2B CD jsr WaitReady_SetATAHeadFromMiscDrvFlags 00CD3E 1 20 10 CD jsr WaitReady_IssueIdentify_CheckErr 00CD41 1 D0 04 bne @ok 00CD43 1 A9 27 lda #PRODOS_IO_ERROR 00CD45 1 38 sec 00CD46 1 60 rts 00CD47 1 00CD47 1 @ok: 00CD47 1 98 48 PHY_OR_TYA_PHA 00CD49 1 A0 00 ldy #0 ; zero loop counter 00CD4B 1 @tossWord: 00CD4B 1 BD 88 C0 lda ATADataLow,x ; Read words 0 thru 56 but throw them away 00CD4E 1 C8 iny 00CD4F 1 C0 39 cpy #57 ; Number of the first word to keep 00CD51 1 D0 F8 bne @tossWord 00CD53 1 68 A8 PLY_OR_PLA_TAY 00CD55 1 00CD55 1 B9 78 07 lda DrvMiscFlags,y 00CD58 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be $40 for this test" 00CD58 1 0A asl a 00CD59 1 0A asl a 00CD5A 1 98 48 PHY_OR_TYA_PHA 00CD5C 1 A0 00 ldy #0 00CD5E 1 90 02 bcc @dev0 00CD60 1 ASSERT BlockOffsetDev1>BlockOffsetDev0, "BlockOffsetDev1 must come after Dev0" 00CD60 1 A0 03 ldy #BlockOffsetDev1-BlockOffsetDev0 00CD62 1 @dev0: 00CD62 1 00CD62 1 38 sec 00CD63 1 BD 88 C0 lda ATADataLow,x ; Read the current capacity in sectors (LBA) 00CD66 1 F9 0F C8 sbc BlockOffsetDev0,y 00CD69 1 85 06 sta blockCount 00CD6B 1 00CD6B 1 BD 80 C0 lda ATADataHigh,x 00CD6E 1 F9 10 C8 sbc BlockOffsetDev0+1,y 00CD71 1 85 07 sta blockCount+1 00CD73 1 00CD73 1 BD 88 C0 lda ATADataLow,x 00CD76 1 F9 11 C8 sbc BlockOffsetDev0+2,y 00CD79 1 85 08 sta blockCount+2 00CD7B 1 00CD7B 1 BD 80 C0 lda ATADataHigh,x 00CD7E 1 E9 00 sbc #0 00CD80 1 F0 08 beq @lessThan8GB 00CD82 1 00CD82 1 A9 FF lda #$ff 00CD84 1 85 06 sta blockCount 00CD86 1 85 07 sta blockCount+1 00CD88 1 85 08 sta blockCount+2 00CD8A 1 00CD8A 1 @lessThan8GB: 00CD8A 1 68 A8 PLY_OR_PLA_TAY 00CD8C 1 00CD8C 1 @tossRemaining: 00CD8C 1 20 08 CD jsr IDEWaitReady ; read the rest of the words, until command ends 00CD8F 1 F0 06 beq @done 00CD91 1 BD 88 C0 lda ATADataLow,x 00CD94 1 4C 8C CD BRA_OR_JMP @tossRemaining 00CD97 1 @done: 00CD97 1 18 clc 00CD98 1 60 rts 00CD99 1 00CD99 1 00CD99 1 ;------------------------------------------------------------------------------ 00CD99 1 ; IsDeviceKnownToExist 00CD99 1 ; 00CD99 1 ; Input: 00CD99 1 ; DrvMiscFlags,y is set up 00CD99 1 ; Y = slot 00CD99 1 ; Output: 00CD99 1 ; BNE = device exists 00CD99 1 ; BEQ = device does not exist 00CD99 1 ;------------------------------------------------------------------------------ 00CD99 1 IsDeviceKnownToExist: 00CD99 1 B9 78 07 lda DrvMiscFlags,y 00CD9C 1 ASSERT kMiscDev1=$40, "kMiscDev1 must be bit 6 for this ASL" 00CD9C 1 0A asl a 00CD9D 1 30 04 bmi @dev1 00CD9F 1 00CD9F 1 B9 78 06 lda PartitionsDev0,y 00CDA2 1 60 rts 00CDA3 1 00CDA3 1 @dev1: 00CDA3 1 B9 F8 06 lda PartitionsDev1,y 00CDA6 1 60 rts 00CDA7 1 00CDA7 1 00CDA7 1 ;------------------------------------------------------------------------------ 00CDA7 1 ; Wait - Copy of Apple's wait routine. Can't use ROM based routine in case 00CDA7 1 ; ROM is not active when we need it. 00CDA7 1 ; 00CDA7 1 ; Input: 00CDA7 1 ; A = desired delay time, where Delay(us) = .5(5A^2 + 27A + 26) 00CDA7 1 ; or more usefully: A = (Delay[in uS]/2.5 + 2.09)^.5 - 2.7 00CDA7 1 ; 00CDA7 1 ; CPU Registers changed: A, P 00CDA7 1 ;------------------------------------------------------------------------------ 00CDA7 1 Wait: 00CDA7 1 38 sec 00CDA8 1 @Wait2: 00CDA8 1 48 pha 00CDA9 1 @Wait3: 00CDA9 1 E9 01 sbc #1 00CDAB 1 D0 FC bne @Wait3 00CDAD 1 68 pla 00CDAE 1 E9 01 sbc #1 00CDB0 1 D0 F6 bne @Wait2 00CDB2 1 60 rts 00CDB3 1 00CDB3 1 ;------------------------------------------------------------------------------ 00CDB3 1 ; RemapAndStoreDriveNum 00CDB3 1 ; 00CDB3 1 ; Input: A = logical drive number (0 = first partition, 1 = second, ...) 00CDB3 1 ; Y = slot 00CDB3 1 ; DrvMiscFlags,Y does not have the kMiscDev1 bit set yet 00CDB3 1 ; BootDevice,Y indicates which device's partitions come first 00CDB3 1 ; BootPartition,Y indicates the boot partition (0=first) 00CDB3 1 ; 00CDB3 1 ; Output: SEC = error (no such partition) 00CDB3 1 ; A = error code 00CDB3 1 ; CLC = no error 00CDB3 1 ; DriveNumber,Y = A = physical drive number 00CDB3 1 ; DrvMiscFlags,Y --> set kMiscDev1 if Dev1 00CDB3 1 ; X and Y are preserved 00CDB3 1 ; 00CDB3 1 ; Bring the desired partition to #0 by swapping it with the first one 00CDB3 1 ; (for example, if you boot from partition #3 then eight 32MB chunks 00CDB3 1 ; on the device appear will in the order: 3, 1, 2, 0, 4, 5, 6, 7). 00CDB3 1 ; 00CDB3 1 ; If you have two devices, all the partitions on the boot device come 00CDB3 1 ; before all the partitions on the non-boot device. 00CDB3 1 ; 00CDB3 1 ; Algorithm: 00CDB3 1 ; 00CDB3 1 ; If BootDevice == Dev0: 00CDB3 1 ; ; Dev0 comes first 00CDB3 1 ; swap 0 with BootPartition 00CDB3 1 ; If P >= NumPartitionsDev0: 00CDB3 1 ; MiscFlags = Dev1 00CDB3 1 ; P -= NumPartitionsDev0 00CDB3 1 ; If P >= NumPartitionsDev1, error. 00CDB3 1 ; Else 00CDB3 1 ; ; Dev1 comes first 00CDB3 1 ; swap 0 with BootPartition 00CDB3 1 ; If P >= NumPartitionsDev1: 00CDB3 1 ; P -= NumPartitionsDev1 00CDB3 1 ; if P >= NumPartitionsDev0, error. 00CDB3 1 ; else 00CDB3 1 ; MiscFlags = Dev1 00CDB3 1 ; 00CDB3 1 ;------------------------------------------------------------------------------ 00CDB3 1 RemapAndStoreDriveNum: 00CDB3 1 48 pha 00CDB4 1 B9 78 05 lda BootDevice,y 00CDB7 1 D0 22 bne @dev1BeforeDev0 00CDB9 1 00CDB9 1 ; Dev0 partitions come first (the normal order) 00CDB9 1 ; 00CDB9 1 ; (1) Swap 0 with BootPartition 00CDB9 1 ; 00CDB9 1 ; (2) if P >= PartitionsDev0: 00CDB9 1 ; MiscFlags = Dev1 00CDB9 1 ; P -= PartitionsDev0 00CDB9 1 ; if P >= PartitionsDev1, error. 00CDB9 1 68 pla 00CDBA 1 F0 09 beq @swapToBootPartition 00CDBC 1 D9 F8 07 cmp BootPartition,y 00CDBF 1 D0 07 bne @haveAdjustedPartitionIndex 00CDC1 1 @physicalZero: 00CDC1 1 A9 00 lda #0 ; map the boot partition's "normal" location to physical 0 00CDC3 1 F0 03 beq @haveAdjustedPartitionIndex 00CDC5 1 @swapToBootPartition: 00CDC5 1 B9 F8 07 lda BootPartition,y ; map 0 to physical location of boot partition 00CDC8 1 @haveAdjustedPartitionIndex: 00CDC8 1 99 F8 04 sta DriveNumber,y 00CDCB 1 38 sec 00CDCC 1 F9 78 06 sbc PartitionsDev0,y ; SBC affects Carry just like CMP 00CDCF 1 90 32 bcc @noError 00CDD1 1 99 F8 04 sta DriveNumber,y 00CDD4 1 D9 F8 06 cmp PartitionsDev1,y 00CDD7 1 B0 22 bcs @tooLarge 00CDD9 1 90 23 bcc @onDev1 00CDDB 1 00CDDB 1 ; Dev1 partitions come first 00CDDB 1 ; 00CDDB 1 ; (1) Swap 0 with BootPartition 00CDDB 1 ; 00CDDB 1 ; (2) if P >= PartitionsDev1: 00CDDB 1 ; P -= PartitionsDev1 00CDDB 1 ; if P >= PartitionsDev0, error. 00CDDB 1 ; else 00CDDB 1 ; MiscFlags = Dev1 00CDDB 1 @dev1BeforeDev0: 00CDDB 1 68 pla 00CDDC 1 F0 09 beq @swapToBootPartitionDev1 00CDDE 1 D9 F8 07 cmp BootPartition,y 00CDE1 1 D0 07 bne @haveAdjustedPartitionIndexDev1 00CDE3 1 @physicalZeroDev1: 00CDE3 1 A9 00 lda #0 00CDE5 1 F0 03 beq @haveAdjustedPartitionIndexDev1 00CDE7 1 @swapToBootPartitionDev1: 00CDE7 1 B9 F8 07 lda BootPartition,y 00CDEA 1 @haveAdjustedPartitionIndexDev1: 00CDEA 1 99 F8 04 sta DriveNumber,y 00CDED 1 38 sec 00CDEE 1 F9 F8 06 sbc PartitionsDev1,y ; SBC affects Carry just like CMP 00CDF1 1 90 0B bcc @onDev1 00CDF3 1 99 F8 04 sta DriveNumber,y 00CDF6 1 D9 78 06 cmp PartitionsDev0,y 00CDF9 1 90 08 bcc @noError 00CDFB 1 @tooLarge: ; carry is already set 00CDFB 1 A9 28 lda #PRODOS_NO_DEVICE 00CDFD 1 ; sec 00CDFD 1 60 rts 00CDFE 1 00CDFE 1 @onDev1: ; carry is already clear 00CDFE 1 A9 40 lda #kMiscDev1 00CE00 1 ; ora DrvMiscFlags,y 00CE00 1 99 78 07 sta DrvMiscFlags,y 00CE03 1 @noError: 00CE03 1 ; clc 00CE03 1 B9 F8 04 lda DriveNumber,y 00CE06 1 60 rts 00CE07 1 00CE07 1 ;============================================================================== 00CE07 1 ;============================================================================== 00CE07 1 00CE07 1 .IF FULL_MENU=0 00CE07 1 ;------------------------------------------------------------------------------ 00CE07 1 ; InteractiveMenu for 6502 00CE07 1 ; 00CE07 1 ; INPUT: X = slot*16, Y = slot 00CE07 1 ; 00CE07 1 ; RTS to caller to continue booting. 00CE07 1 ;------------------------------------------------------------------------------ 00CE07 1 InteractiveMenu_Impl: 00CE07 1 rts 00CE07 1 .ELSE 00CE07 1 ;------------------------------------------------------------------------------ 00CE07 1 ; InteractiveMenu_Impl 00CE07 1 ; 00CE07 1 ; INPUT: X = slot*16, Y = slot 00CE07 1 ; 00CE07 1 ; RTS to caller to continue booting. 00CE07 1 ;------------------------------------------------------------------------------ 00CE07 1 kMenuInteractiveRows = 4 00CE07 1 kMenuTotalRows = 5 00CE07 1 00CE07 1 kRowPartitionsDev0 = 0 00CE07 1 kRowPartitionsDev1 = 1 00CE07 1 kRowBootDevice = 2 00CE07 1 kRowBootPartition = 3 00CE07 1 kRowBootSaveQuit = 4 00CE07 1 00CE07 1 ASSERT (Max32MBPartitionsDev0-Max32MBPartitionsDev0)=kRowPartitionsDev0, "oops" 00CE07 1 ASSERT (Max32MBPartitionsDev1-Max32MBPartitionsDev0)=kRowPartitionsDev1, "oops" 00CE07 1 ASSERT (DefaultBootDevice-Max32MBPartitionsDev0)=kRowBootDevice, "oops" 00CE07 1 ASSERT (DefaultBootPartition-Max32MBPartitionsDev0)=kRowBootPartition, "oops" 00CE07 1 00CE07 1 kMenuTop = 10 00CE07 1 kMenuBootSaveQuitLine = 21 00CE07 1 00CE07 1 kMenuAlignment = 20 00CE07 1 00CE07 1 menuVTAB: 00CE07 1 0A .byte kMenuTop 00CE08 1 0B .byte kMenuTop+1 00CE09 1 0D .byte kMenuTop+3 00CE0A 1 0E .byte kMenuTop+4 00CE0B 1 15 .byte kMenuBootSaveQuitLine 00CE0C 1 menuHTAB: 00CE0C 1 03 .byte kMenuAlignment-15-2 00CE0D 1 0E .byte kMenuAlignment-4-2 00CE0E 1 0A .byte kMenuAlignment-8-2 00CE0F 1 09 .byte kMenuAlignment-9-2 00CE10 1 08 .byte 8 00CE11 1 menuRowText: 00CE11 1 1C .byte MsgMenuRow0-Messages 00CE12 1 2B .byte MsgMenuRow1-Messages 00CE13 1 2F .byte MsgMenuRow2-Messages 00CE14 1 37 .byte MsgMenuRow3-Messages 00CE15 1 40 .byte MsgBootSaveQuit-Messages 00CE16 1 menuMinimumValues: 00CE16 1 00 00 00 01 .byte 0, 0, 0, 1 00CE1A 1 menuMaximumValuesPlusOne: 00CE1A 1 0E 0E 02 0E .byte 13+1, 13+1, 1+1, 13+1 00CE1E 1 00CE1E 1 00CE1E 1 InteractiveMenu_Impl: 00CE1E 1 86 41 stx menuSlot16 00CE20 1 84 40 sty menuSlot 00CE22 1 ; Intentionally change $01 so that monitor SLOOP won't continue the boot scan. 00CE22 1 84 01 sty $01 ; store anything *other* than $Cn 00CE24 1 00CE24 1 ; Reset goes to BASIC 00CE24 1 .if USE_65C02 00CE24 1 stz ResetVector 00CE24 1 .else 00CE24 1 A9 00 lda #