;AppleWin : An Apple //e emulator for Windows ; ;Copyright (C) 1994-1996, Michael O'Brien ;Copyright (C) 1999-2001, Oliver Schmidt ;Copyright (C) 2002-2005, Tom Charlesworth ;Copyright (C) 2006-2012, Tom Charlesworth, Michael Pohoreski ; ;AppleWin is free software; you can redistribute it and/or modify ;it under the terms of the GNU General Public License as published by ;the Free Software Foundation; either version 2 of the License, or ;(at your option) any later version. ; ;AppleWin is distributed in the hope that it will be useful, ;but WITHOUT ANY WARRANTY; without even the implied warranty of ;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;GNU General Public License for more details. ; ;You should have received a copy of the GNU General Public License ;along with AppleWin; if not, write to the Free Software ;Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ; ; Description: Firmware for harddisk card ; ; Author: Copyright (c) 2005, Robert Hoem ; ; Modified by Tom Charlesworth: ; . Updated so it can be assembled by ACME 0.97 ; . Fixed so that ProDOS entrypoint is $c70a (26 Dev 2007) (Bug #12723) ; . Modified to support Apple Oasis' entrypoint: $c761 (8 Sept 2012) (Feature #5557) ; . Added support for SmartPort entrypoint (20 Oct 2012) ; - EG. "Prince of Persia (Original 3.5 floppy for IIc+).2mg" ; . GH#370 (Robert Hoem, 27 Oct 2016): ; . Added a check against open-apple during boot to route boot to slot 6 ; . This happens after the first two blocks are loaded from the HD. ; . GH#319: SmartPort return address wrong when crossing page ; . GH#996: Make code slot-independent (so HDD controller card can go into any slot) ; . Moved the 512-byte block read into AppleWin's HDD emulation (to mirror the block write command) ; TODO: ; . Remove support for Entrypoint_Cs46 (old AppleWin) & Entrypoint_Cs61 (Apple Oasis) ; - provide a utility to convert these to use Entrypoint_ProDOS ; . Check SmartPort: Is it OK to trash Y and $42,..,$47 ? ; !cpu 6502 ; Compatible with all Apple2's !to "hddrvr.bin", plain !sl "hddrvr.labels" ; constants hd_execute = $c080 hd_status = $c081 ; b7=busy, b0=error hd_command = $c082 hd_unitnum = $c083 hd_memblock = $c084 hd_diskblock = $c086 ;hd_nextbyte = $c088 ; legacy read-only port (still supported by AppleWin) ; Notes on accesses to I/O registers: ; . ROR ABS16,X and ROL ABS16,X - only used for $C081+s*$10 STATUS register: ; 6502: double read (old data), write (old data), write (new data). The writes are harmless as writes to STATUS are ignored. ; 65C02: double read (old data), write (new data). The write is harmless as writes to STATUS are ignored. ; . STA ABS16,X does a false-read. This is harmless for writable I/O registers, since the false-read has no side effect. command = $42 unitnum = $43 memblock = $44 diskblock = $46 slot6 = $C600 OS = $0801 BUTTON0 = $C061 ;====================================== !zone code *= $0000 ; org $0000 - position-independent code, so doesn't matter (but the other fixed org positions need to be on the same page) ; The Autoboot rom will call this. ; This is also the entry point for such things as IN#7 and PR#7 start ; Autoboot and ProDOS look at the following few opcodes to detect block devices ; NB. $Cn07 should be $00 for a SmartPort Interface, but changing this means that it won't autoboot on ][, ][+ and unenhanced IIe. ; . ref: http://www.1000bit.it/support/manuali/apple/technotes/udsk/tn.udsk.2.html lda #$20 lda #$00 lda #$03 lda #$3C bne Bootstrap Entrypoint_ProDOS ; $Cn0A - ProDOS entrypoint sec bcs Entrypoint Entrypoint_SmartPort ; $Cn0D - SmartPort entrypoint clc Entrypoint ; $Cn0E - entrypoint? bcs GetSlotInX ; C=1: GetSlotInX -> cmdproc ; C=0: fall through to SmartPort... ;====================================== ; TODO: Is it OK to trash Y and $42,..,$47 ? ; Pre: C=0, X = Slot# << 4 SmartPort ; SmartPort -> GetSlotInX -> cmdproc pla sta $46 adc #3 ; Pre: C=0, Post: C=0 or 1 tay pla sta $47 ; ($46) = &cmd_hdr adc #0 pha tya pha ; (sp).w += 3 ldy #1 lda ($46),y ; cmd sta $42 iny lda ($46),y ; param_l sta $45 iny lda ($46),y ; param_h sta $46 ldy #1 ; skip paramLength (assume it's #$03) lda ($45),y ; unit sta $43 iny lda ($45),y ; memblock_l sta $44 iny lda ($45),y ; memblock_h pha iny lda ($45),y ; diskblock_l pha iny bne SmartPort2 ;====================================== ; 2 unused bytes @checkCs46 *= $0046 ; org $0046 !warn "Cs46 padding = ", * - @checkCs46 Entrypoint_Cs46 ; Old f/w 'cmdproc' entrypoint ; Keep this for any DOSMaster HDD images created with old AppleWin HDD f/w. ; DOSMaster hardcodes the entrypoint addr into its bootstrapping code: ; - So DOSMaster images are tied to the HDD's controller's f/w sec bcs Entrypoint ; or directly to GetSlotInX ;====================================== Bootstrap ; Lets check to see if there's an image ready ; Slot n, disk 1 clc bcc GetSlotInX ; Post: X = Slot# << 4 Bootstrap2 lda #$00 sta hd_unitnum,x ; b7=0 => disk 1 sta hd_command,x lda hd_execute,x ror hd_status,x ; Post: C=0 or 1 bcc hdboot ; no image ready, boot diskette image instead BootSlot6 jmp slot6 ;====================================== ; 2 unused bytes @checkCs61 *= $0061 ; org $0061 !warn "Cs61 padding = ", * - @checkCs61 Entrypoint_Cs61 ; Apple Oasis HDD controller entrypoint ; Keep this for any DOSMaster HDD images created with Apple Oasis HDD f/w. ; DOSMaster hardcodes the entrypoint addr into its bootstrapping code: ; - So DOSMaster images are tied to the HDD's controller's f/w sec bcs Entrypoint ; or directly to GetSlotInX ;====================================== ; image ready. Lets boot from it. ; we want to load block 1 from disk 1 to $800 then jump there ; Pre: X = Slot# << 4 ; C = 0 hdboot lda #$0 sta unitnum ; b7=0 => disk 1 sta memblock sta diskblock sta diskblock+1 lda #$8 sta memblock+1 lda #$1 sta command bne cmdproc hdboot2 bcs BootSlot6 bit BUTTON0 ; button 0 pressed? bmi BootSlot6 ; Pre: X = Slot# << 4 jmp OS ;====================================== SmartPort2 lda ($45),y ; diskblock_h sta $47 pla sta $46 pla sta $45 sec ; fall through... ;====================================== ; Pre: ; C=0 => via Bootstrap ; C=1 => via Entrypoint / SmartPort2 ; Post: ; X = Slot# << 4 GetSlotInX php sei ; disable ints, in case an int handler races our $0000/RTS and stack accesses! ; NB. need RAM that's guaranteed to be both read & writeable: ; . can't use $0200-$BFFF, due to eg. RAMRD=0/RAMWRT=1 combination ; . can't use LC as ROM might be enabled. ; So use ZP (specifically $0000) as whatever the state of ALTZP, both read & write will be to the same physical memory location. lda $00 ; save $00 ldx #$60 ; opcode RTS stx $00 jsr $0000 ; RTS immediately (NB. can't use $FF58, since LC RAM may be switched in) sta $00 ; restore $00 tsx lda $0100,x ; $Cn asl asl asl asl tax ; X=$n0 plp ; + restore int status bcc Bootstrap2 ; otherwise fall through for Entrypoint / SmartPort... ;-------------------------------------- ; entry point for ProDOS' block driver ; simple really. Copy the command from $42..$47 ; to our I/O ports then execute command ; Pre: ; C=0 => via Bootstrap (hdboot) ; C=1 => via GetSlotInX (eg. Entrypoint / SmartPort2) ; X = Slot# << 4 ; Post: ; C = hd_status.b0 ; A = result of hd_execute ; X = Slot# << 4 cmdproc php lda command sta hd_command,x lda unitnum sta hd_unitnum,x lda memblock sta hd_memblock,x lda memblock+1 sta hd_memblock+1,x lda diskblock sta hd_diskblock,x lda diskblock+1 sta hd_diskblock+1,x lda hd_execute,x ; A = result of hd_execute (NB. instantaneous 512 byte r/w!) - rol hd_status,x ; b7=busy doing DMA? bcs - plp ; restore C from start of cmdproc bcs done ror hd_status,x ; Post: C=0 or 1 lda #0 beq hdboot2 done ror hd_status,x ; Post: C=0 or 1 rts ;====================================== ; 33 unused bytes !zone data ; $CsFE = status bits (BAP p7-14) ; 7 = medium is removable ; 6 = device is interruptable ; 5-4 = number of volumes (0..3 means 1..4) ; 3 = device supports Format call ; 2 = device can be written to ; 1 = device can be read from (must be 1) ; 0 = device status can be read (must be 1) ; $C7 = Removable, Interruptable, #Volumes=1, Supports write/read/status ; $D7 = Removable, Interruptable, #Volumes=2, Supports write/read/status ; $BF = Removable, Interruptable, #Volumes=4, Supports format/write/read/status (KEGS / IIGS) ; datablock. This starts near the end of the firmware (at offset $FC) ;; data @checkCsFC *= $00FC ; org $00FC !warn "CsFC padding = ", * - @checkCsFC !word $7fff ; how many blocks are on the device. !byte $D7 ; specifics about the device (number of drives, read/write/format capability, etc) !byte