ca65 V2.18 - Raspbian 2.19-1
Main file   : DriveFirmware.asm
Current file: DriveFirmware.asm

000000r 1               ; Copyright Terence J. Boldt (c)2020-2022
000000r 1               ; Use of this source code is governed by an MIT
000000r 1               ; license that can be found in the LICENSE file.
000000r 1               
000000r 1               ; This file contains the source for the firmware
000000r 1               ; that allows the Apple II to boot from the card
000000r 1               ; and for ProDOS to recognize the card as two
000000r 1               ; hard drivers
000000r 1               
000000r 1               ;ProDOS Zero Page
000000r 1               Command = $42 ;ProDOS Command
000000r 1               Unit = $43 ;ProDOS unit (SDDD0000)
000000r 1               BufferLo = $44
000000r 1               BufferHi = $45
000000r 1               BlockLo = $46
000000r 1               BlockHi = $47
000000r 1               
000000r 1               ; ProDOS Error Codes
000000r 1               IOError = $27
000000r 1               NoDevice = $28
000000r 1               WriteProtect = $2B
000000r 1               
000000r 1               InputByte = $c08e+SLOT*$10
000000r 1               OutputByte = $c08d+SLOT*$10
000000r 1               InputFlags = $c08b+SLOT*$10
000000r 1               OutputFlags = $c087+SLOT*$10
000000r 1               
000000r 1               ReadBlockCommand = $01
000000r 1               WriteBlockCommand = $02
000000r 1               GetTimeCommand = $03
000000r 1               ChangeDriveCommand = $04
000000r 1               ExecCommand = $05
000000r 1               LoadFileCommand = $06
000000r 1               SaveFileCommand = $07
000000r 1               MenuCommand = $08
000000r 1               
000000r 1                .org SLOT*$100 + $C000
00C700  1               ;ID bytes for booting and drive detection
00C700  1  E0 20         cpx #$20    ;ID bytes for ProDOS and the
00C702  1  E0 00         cpx #$00    ; Apple Autostart ROM
00C704  1  E0 03         cpx #$03    ;
00C706  1               
00C706  1  A2 70         ldx #SLOT*$10
00C708  1  86 2B         stx $2b
00C70A  1  86 43         stx Unit
00C70C  1               
00C70C  1               ;force EPROM to second page on boot
00C70C  1  A9 3F         lda #$3f ;set all flags high and page 3 of EPROM for menu
00C70E  1               PageJump:
00C70E  1  8D F7 C0      sta OutputFlags
00C711  1  4C 1C C7      jmp Start ;this jump is only called if coming in from PageJump with A=$0f
00C714  1               
00C714  1               ;entry points for ProDOS
00C714  1               DriverEntry:
00C714  1  A9 0F         lda #$0f ;set all flags high and page 0 of EPROM
00C716  1  8D F7 C0      sta OutputFlags
00C719  1  4C 32 C7      jmp Driver
00C71C  1               
00C71C  1               ;load first two blocks and execute to boot
00C71C  1               Start:
00C71C  1  A9 01         lda     #$01    ;set read command
00C71E  1  85 42         sta     Command
00C720  1               
00C720  1  A9 00         lda     #$00    ;block 0
00C722  1  85 46         sta     BlockLo
00C724  1  85 47         sta     BlockHi
00C726  1  85 44         sta     BufferLo   ;buffer at $800
00C728  1  A9 08         lda     #$08
00C72A  1  85 45         sta     BufferHi
00C72C  1  20 32 C7      jsr     Driver  ;get the block
00C72F  1               
00C72F  1  4C 01 08      jmp     $801    ;execute the block
00C732  1               
00C732  1               ; ProDOS Driver code
00C732  1               ; First check that this is the right drive
00C732  1               Driver:
00C732  1  A6 43         ldx Unit
00C734  1  A5 42         lda Command; Check which command is being requested
00C736  1  F0 0C         beq GetStatus ;0 = Status command
00C738  1  C9 01         cmp #ReadBlockCommand
00C73A  1  F0 10         beq ReadBlockAndSetTime
00C73C  1  C9 02         cmp #WriteBlockCommand
00C73E  1  F0 54         beq WriteBlock
00C740  1  38            sec ;set carry as we don't support any other commands
00C741  1  A9 53         lda #$53 ;Invalid parameter error
00C743  1  60            rts
00C744  1               
00C744  1               ; ProDOS Status Command Handler
00C744  1               GetStatus:
00C744  1  A2 FF         ldx #$ff ;low byte number of blocks
00C746  1  A0 FF         ldy #$ff ;high byte number of blocks
00C748  1  A9 00         lda #$0 ;zero accumulator and clear carry for success
00C74A  1  18            clc
00C74B  1  60            rts
00C74C  1               
00C74C  1               ; ProDOS Read Block Command
00C74C  1               ReadBlockAndSetTime:
00C74C  1  A5 47         lda BlockHi ; only get the time if block 0002
00C74E  1  D0 18         bne readBlock
00C750  1  A5 46         lda BlockLo
00C752  1  C9 02         cmp #$02
00C754  1  D0 12         bne readBlock
00C756  1  A0 00         ldy #$00 ;Get the current time on each block read for now
00C758  1  A9 03         lda #GetTimeCommand
00C75A  1  20 C0 C7      jsr SendByte
00C75D  1               getTimeByte:
00C75D  1  20 DE C7      jsr GetByte
00C760  1  99 90 BF      sta $bf90,y
00C763  1  C8            iny
00C764  1  C0 04         cpy #$04
00C766  1  D0 F5         bne getTimeByte
00C768  1               readBlock:
00C768  1  A9 01         lda #ReadBlockCommand ;read the block after setting the clock
00C76A  1  20 C0 C7      jsr SendByte
00C76D  1  A5 46         lda BlockLo
00C76F  1  20 C0 C7      jsr SendByte
00C772  1  A5 47         lda BlockHi
00C774  1  20 C0 C7      jsr SendByte
00C777  1  8A            txa
00C778  1  20 C0 C7      jsr SendByte
00C77B  1  A0 00         ldy #$0
00C77D  1  20 8B C7      jsr read256
00C780  1  E6 45         inc BufferHi
00C782  1  20 8B C7      jsr read256
00C785  1  C6 45         dec BufferHi
00C787  1  A9 00         lda #$0 ;zero accumulator and clear carry for success
00C789  1  18            clc
00C78A  1  60            rts
00C78B  1               
00C78B  1               read256:
00C78B  1  20 DE C7      jsr GetByte
00C78E  1  91 44         sta (BufferLo),y
00C790  1  C8            iny
00C791  1  D0 F8         bne read256
00C793  1  60            rts
00C794  1               
00C794  1               ; ProDOS Write Block Command
00C794  1               WriteBlock:
00C794  1  A9 02         lda #WriteBlockCommand
00C796  1  20 C0 C7      jsr SendByte
00C799  1  A5 46         lda BlockLo
00C79B  1  20 C0 C7      jsr SendByte
00C79E  1  A5 47         lda BlockHi
00C7A0  1  20 C0 C7      jsr SendByte
00C7A3  1  8A            txa
00C7A4  1  20 C0 C7      jsr SendByte
00C7A7  1  A0 00         ldy #$0
00C7A9  1  20 B7 C7      jsr write256
00C7AC  1  E6 45         inc BufferHi
00C7AE  1  20 B7 C7      jsr write256
00C7B1  1  C6 45         dec BufferHi
00C7B3  1  A9 00         lda #$0 ;zero accumulator and clear carry for success
00C7B5  1  18            clc
00C7B6  1  60            rts
00C7B7  1               
00C7B7  1               write256:
00C7B7  1  B1 44         lda (BufferLo),y
00C7B9  1  20 C0 C7      jsr SendByte
00C7BC  1  C8            iny
00C7BD  1  D0 F8         bne write256
00C7BF  1  60            rts
00C7C0  1               
00C7C0  1               SendByte:
00C7C0  1  48            pha
00C7C1  1               waitWrite:
00C7C1  1  AD FB C0      lda InputFlags
00C7C4  1  2A            rol
00C7C5  1  2A            rol
00C7C6  1  B0 F9         bcs waitWrite
00C7C8  1  68            pla
00C7C9  1  8D FD C0      sta OutputByte
00C7CC  1  A9 0E         lda #$0e ; set bit 0 low to indicate write started
00C7CE  1  8D F7 C0      sta OutputFlags
00C7D1  1               finishWrite:
00C7D1  1  AD FB C0      lda InputFlags
00C7D4  1  2A            rol
00C7D5  1  2A            rol
00C7D6  1  90 F9         bcc finishWrite
00C7D8  1  A9 0F         lda #$0f
00C7DA  1  8D F7 C0      sta OutputFlags
00C7DD  1  60            rts
00C7DE  1               
00C7DE  1               GetByte:
00C7DE  1  A9 0D         lda #$0d ;set read flag low
00C7E0  1  8D F7 C0      sta OutputFlags
00C7E3  1               waitRead:
00C7E3  1  AD FB C0      lda InputFlags
00C7E6  1  2A            rol
00C7E7  1  B0 FA         bcs waitRead
00C7E9  1  AD FE C0      lda InputByte
00C7EC  1  48            pha
00C7ED  1  A9 0F         lda #$0f ;set all flags high
00C7EF  1  8D F7 C0      sta OutputFlags
00C7F2  1               finishRead:
00C7F2  1  AD FB C0      lda InputFlags
00C7F5  1  2A            rol
00C7F6  1  90 FA         bcc finishRead
00C7F8  1  68            pla
00C7F9  1               end:
00C7F9  1  60            rts
00C7FA  1               
00C7FA  1  00 00        .repeat	251-<end
00C7FC  1               .byte 0
00C7FC  1               .endrepeat
00C7FC  1               
00C7FC  1  00 00        .byte      0,0     ;0000 blocks = check status
00C7FE  1  17           .byte      23       ;bit set(0=status 1=read 2=write) unset(3=format, 4/5=number of volumes, 6=interruptable, 7=removable)
00C7FF  1  14           .byte     DriverEntry&$00FF ;low byte of entry
00C800  1               
00C800  1               
