a3DriverDepot/drivers/cffa3000/CFFA3000.s

985 lines
36 KiB
ArmAsm

; CFFA3000
; .TITLE "Apple /// Compact Flash For Apple 3000 (CFFA3000) Driver"
.PROC CFFA3000
.feature labels_without_colons
.setcpu "6502"
.reloc
DriverVersion = $1000 ; Version number
DriverMfgr = $4453 ; Driver Manufacturer - DS
;
; SOS Equates
;
ExtPG = $1401 ; Driver extended bank address offset
AllocSIR = $1913 ; Allocate system internal resource
SELC800 = $1922 ; Enable Expansion ROM Space
SysErr = $1928 ; Report error to system
EReg = $FFDF ; Environment register
ReqCode = $C0 ; Request code
SOS_Unit = $C1 ; Unit number
SosBuf = $C2 ; SOS buffer pointer (2 bytes)
ReqCnt = $C4 ; Requested byte count
CtlStat = $C2 ; Control/status code
CSList = $C3 ; Control/status list pointer
SosBlk = $C6 ; Starting block number
QtyRead = $C8 ; Pointer to bytes read return by D_READ
;
; Our temps in zero page
;
Count = $CD ; 2 bytes
C800Ptr = $CF ; 2 bytes
;
; Parameter block specific to current SOS request
;
CFFAUnit = $D1
Num_Blks = $D4 ; 2 bytes lsb, msb
DataBuf = $D6 ; 2 bytes
;
; SOS Error Codes
;
XDNFERR = $10 ; Device not found
XBADDNUM = $11 ; Invalid device number
XREQCODE = $20 ; Invalid request code
XCTLCODE = $21 ; Invalid control/status code
XCTLPARAM = $22 ; Invalid control/status parameter
XNORESRC = $25 ; Resources not available
XBADOP = $26 ; Invalid operation
XIOERROR = $27 ; I/O error
XNODRIVE = $28 ; Drive not connected
XBYTECNT = $2C ; Byte count not a multiple of 512
XBLKNUM = $2D ; Block number to large
XDISKSW = $2E ; Disk switched
XNORESET = $33 ; Device reset failed
;
; CFFA3000 Constants
;
kCmd3K_SetEnvironment = $01 ; Set X = 0xa3 for Apple ///
kCmd3K_Status = $10
kCmd3K_Read = $11
kCmd3K_Write = $12
CFFA3K_API = $CFED ; CFFA3000 API entry point
shUnitNumber = $CFDF
shStatusByte = $CFE0
shBlockNumber = $CFE1
;
; Switch Macro
;
.MACRO SWITCH index,bounds,adrs_table,noexec ;See SOS Reference
.IFNBLANK index ;If PARM1 is present,
LDA index ; load A with switch index
.ENDIF
.IFNBLANK bounds ;If PARM2 is present,
CMP #bounds+1 ; perform bounds checking
BCS @110 ; on switch index
.ENDIF
ASL A ;Multiply by 2 for table index
TAY
LDA adrs_table+1,Y ;Get switch address from table
PHA ; and push onto Stack
LDA adrs_table,Y
PHA
.IFBLANK noexec
; .IF noexec <> '*' ;If PARM4 is omitted,
RTS ; exit to code
; .ENDIF
.ENDIF
@110
.ENDMACRO
.SEGMENT "TEXT"
;
; Comment Field of driver
;
.WORD $FFFF ; Signal that we have a comment
.WORD COMMENT_END - COMMENT
COMMENT: .BYTE "Apple /// CFFA3000 (Compact Flash For Apple 3000) Driver by David Schmidt 2018"
COMMENT_END:
.SEGMENT "DATA"
;------------------------------------
;
; Device identification Block (DIB) - Volume #0
;
;------------------------------------
DIB_0 .WORD DIB_1 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D1 "; Device name
.BYTE $80 ; Active, no page alignment
DIB0_Slot .BYTE $01 ; Slot number
.BYTE $00 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB0_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #1
; Page alignment begins here
;
DIB_1 .WORD DIB_2 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D2 "; Device name
.BYTE $80 ; Active
DIB1_Slot .BYTE $01 ; Slot number
.BYTE $01 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB1_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #2
;
DIB_2 .WORD DIB_3 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D3 "; Device name
.BYTE $80 ; Active
DIB2_Slot .BYTE $01 ; Slot number
.BYTE $02 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB2_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #3
;
DIB_3 .WORD DIB_4 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D4 "; Device name
.BYTE $80 ; Active
DIB3_Slot .BYTE $01 ; Slot number
.BYTE $03 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB3_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #4
;
DIB_4 .WORD DIB_5 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D5 "; Device name
.BYTE $80 ; Active
DIB4_Slot .BYTE $01 ; Slot number
.BYTE $04 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB4_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #5
;
DIB_5 .WORD DIB_6 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D6 "; Device name
.BYTE $80 ; Active
DIB5_Slot .BYTE $01 ; Slot number
.BYTE $05 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB5_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #6
;
DIB_6 .WORD DIB_7 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D7 "; Device name
.BYTE $80 ; Active
DIB6_Slot .BYTE $01 ; Slot number
.BYTE $06 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB6_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;
; Device identification Block (DIB) - Volume #7
;
DIB_7 .WORD $0000 ; Link pointer
.WORD Entry ; Entry pointer
.BYTE $0B ; Name length byte
.BYTE ".CFFA3000D8 "; Device name
.BYTE $80 ; Active
DIB7_Slot .BYTE $01 ; Slot number
.BYTE $07 ; Unit number
.BYTE $F1 ; Type
.BYTE $10 ; Subtype
.BYTE $00 ; Filler
DIB7_Blks .WORD $0000 ; # Blocks in device
.WORD DriverMfgr ; Driver manufacturer
.WORD DriverVersion ; Driver version
.WORD $0000 ; DCB length followed by DCB
;------------------------------------
;
; Local storage locations
;
;------------------------------------
LastOP .RES $08, $FF ; Last operation for D_REPEAT calls
SIR_Addr .WORD SIR_Tbl
SIR_Tbl .RES $05, $00
SIR_Len = *-SIR_Tbl
RdBlk_Proc .WORD $0000
WrBlk_Proc .WORD $0000
MaxUnits .BYTE $00 ; The maximum number of units
DCB_Idx .BYTE $00 ; DCB 0's blocks
.BYTE DIB1_Blks-DIB0_Blks ; DCB 1's blocks
.BYTE DIB2_Blks-DIB0_Blks ; DCB 2's blocks
.BYTE DIB3_Blks-DIB0_Blks ; DCB 3's blocks
.BYTE DIB4_Blks-DIB0_Blks ; DCB 4's blocks
.BYTE DIB5_Blks-DIB0_Blks ; DCB 5's blocks
.BYTE DIB6_Blks-DIB0_Blks ; DCB 6's blocks
.BYTE DIB7_Blks-DIB0_Blks ; DCB 7's blocks
SigCF3K .BYTE "CF3K" ; CFFA3000 signature in memory
CardIsOK .BYTE $00 ; Have we found the CFFA3000 yet?
LastError .BYTE $00 ; Recent error RC from CFFA3000
;------------------------------------
;
; Driver request handlers
;
;------------------------------------
Entry LDA DIB0_Slot
JSR SELC800 ; Turn on C800 ROM space from our slot
LDA SOS_Unit
STA CFFAUnit
INC CFFAUnit ; CFFA3000 unit is 1-based vs. SOS 0-based
JSR Dispatch ; Call the dispatcher
LDX SOS_Unit ; Get drive number for this unit
LDA ReqCode ; Keep request around for D_REPEAT
STA LastOP,X ; Keep track of last operation
LDA #$00
JSR SELC800 ; Unselect C800 ROM space
RTS
;
; The Dispatcher. Note that if we came in on a D_INIT call,
; we do a branch to Dispatch normally.
; Dispatch is called as a subroutine!
;
DoTable .WORD DRead-1 ; 0 Read request
.WORD DWrite-1 ; 1 Write request
.WORD DStatus-1 ; 2 Status request
.WORD DControl-1 ; 3 Control request
.WORD BadReq-1 ; 4 Unused
.WORD BadReq-1 ; 5 Unused
.WORD BadOp-1 ; 6 Open - valid for character devices
.WORD BadOp-1 ; 7 Close - valid for character devices
.WORD DInit-1 ; 8 Init request
.WORD DRepeat-1 ; 9 Repeat last read or write request
Dispatch SWITCH ReqCode,9,DoTable ; Serve the request
;
; Dispatch errors
;
BadReq LDA #XREQCODE ; Bad request code!
JSR SysErr ; Return to SOS with error in A
BadOp LDA #XBADOP ; Invalid operation!
JSR SysErr ; Return to SOS with error in A
;
; D_REPEAT - repeat the last D_READ or D_WRITE call
;
DRepeat LDX SOS_Unit
LDA LastOP,X ; Recall the last thing we did
CMP #$02 ; Looking for operation < 2
BCS BadOp ; Can only repeat a read or write
STA ReqCode
JMP Dispatch
NoDevice LDA #XDNFERR ; Device not found
JSR SysErr ; Return to SOS with error in A
;
; D_INIT call processing - called once each for all volumes.
;
DInit LDA SOS_Unit ; Check if we're initting the zeroeth unit
BNE UnitInit ; No - then skip the signature check
CheckSig LDA #$C0 ; Form a $CsF6 address, where s = slot #
ORA DIB0_Slot ; Add in slot number
STA Count+1
LDA #$F6
STA Count
LDY #$03
@1 LDA (Count),Y
CMP SigCF3K,Y ; Check for 'CF3K' signature in our slot
BNE NoDevice ; No device if all four bytes don't match
DEY
BPL @1
LDA DIB0_Slot ; Found a CFFA3000!
ORA #$10 ; SIR = 16+slot#
STA SIR_Tbl
STA CardIsOK ; Remember that we found the card
LDA #SIR_Len
LDX SIR_Addr
LDY SIR_Addr+1
JSR AllocSIR ; This one's mine!
BCS NoDevice
LDX #$A3
LDA #kCmd3K_SetEnvironment
JSR CFFA3K_API ; Get CFFA3000 set up for us
BCS NoDevice
LDA #$00
STA shUnitNumber
LDA #kCmd3K_Status
JSR CFFA3K_API ; How many units can we expect at maximum?
BCS NoDevice
LDA shUnitNumber
STA MaxUnits
UnitInit
LDA CardIsOK ; Did we previously find a card?
BEQ NoDevice ; If not... then bail
LDA CFFAUnit ; Which unit did we get called with?
STA shUnitNumber
LDA #kCmd3K_Status ; Ask for the status of this unit
JSR CFFA3K_API
LDA #$00
STA shBlockNumber
STA shBlockNumber+1
STA shBlockNumber+2
STA shBlockNumber+3
LDA #kCmd3K_Read ; Do a dummy read of block zero
JSR CFFA3K_API ; to clear out a device switched error
LDA #kCmd3K_Status
JSR CFFA3K_API
BCS NoDevice
SaveCapacity
LDX SOS_Unit ; Get the stats on this unit
LDY DCB_Idx,X
LDA shBlockNumber
STA DIB0_Blks,Y
LDA shBlockNumber+1
STA DIB0_Blks+1,Y
LDA shBlockNumber+2
CMP #$01 ; Do we have 65536 (or more) blocks?
BNE UIDone
LDA #$FF ; Then we really only have 65535 blocks.
STA DIB0_Blks,Y
STA DIB0_Blks+1,Y
UIDone CLC
RTS
;
; D_READ call processing
;
DRead
LDA CardIsOK ; Did we previously find a card?
BNE DReadGo
JMP NoDevice ; If not... then bail
DReadGo
JSR CkCnt ; Checks for validity, aborts if not
JSR CkUnit ; Checks for unit below unit max
LDA #$00 ; Zero # bytes read
STA Count ; Local count of bytes read
STA Count+1
TAY
STA (QtyRead),Y ; Userland count of bytes read
INY
STA (QtyRead),Y ; Msb of userland bytes read
LDA Num_Blks ; Check for Num_Blks greater than zero
ORA Num_Blks+1
BEQ ReadExit
JSR FixUp ; Correct for addressing anomalies
JSR Read_Block ; Transfer a block to/from the disk
LDY #$00
LDA Count ; Local count of bytes read
STA (QtyRead),y ; Update # of bytes actually read
INY
LDA Count+1
STA (QtyRead),y
BCS IO_Error ; An error occurred
ReadExit RTS ; Exit read routines
IO_Error LDA #XIOERROR ; I/O error
JSR SysErr ; Return to SOS with error in A
;
; D_WRITE call processing
;
DWrite
LDA CardIsOK ; Did we previously find a card?
BNE DWriteGo
JMP NoDevice ; If not... then bail
DWriteGo
JSR CkCnt ; Checks for validity
JSR CkUnit ; Checks for unit below unit max
CWrite LDA Num_Blks ; Check for Num_Blks greater than zero
ORA Num_Blks+1
BEQ WriteExit ; Quantity to write is zero - so done
JSR FixUp
JSR Write_Block
BCS IO_Error
WriteExit RTS
;
; D_STATUS call processing
; $00 = Driver Status
; $FE = Return preferrred bitmap location ($FFFF)
;
DStatus
LDA CardIsOK ; Did we previously find a card?
BNE DStatusGo
JMP NoDevice ; If not... then bail
DStatusGo
LDA CFFAUnit ; Get the unit number we're talking about
STA shUnitNumber
LDA CtlStat ; Which status code to run?
BNE DS0
LDA #kCmd3K_Status ; Status code 0 - return the status byte
JSR CFFA3K_API
BCS DS1
LDY #$00
LDA shStatusByte
STA (CSList),Y
JSR SaveCapacity
CLC
RTS
DS1 CMP #$2F ; Did we get a fancy new $2f error?
BNE DS2
LDA #XDNFERR ; Then change it to XDNFERR instead.
DS2 JSR SysErr ; Return to SOS with error in A
DS0 CMP #$FE
BNE DSWhat
LDY #$00 ; Return preferred bit map locations.
LDA #$FF ; We return FFFF, don't care
STA (CSList),Y
INY
STA (CSList),Y
CLC
RTS
DSWhat LDA #XCTLCODE ; Control/status code no good
JSR SysErr ; Return to SOS with error in A
;
; D_CONTROL call processing
; $00 = Reset device
; $FE = Perform media formatting
;
DControl
LDA CardIsOK ; Did we previously find a card?
BNE DContGo
JMP NoDevice ; If not... then bail
DContGo LDA CtlStat ; Control command
BEQ CReset
CMP #$FE ; Format?
BEQ DCFormat
JMP DCWhat ; Control code no good!
CReset JSR UnitInit ; Reset this unit
BCS DCNoReset
DCDone RTS
DCNoReset LDA #XNORESET ; Things went bad after reset
JSR SysErr ; Return to SOS with error in A
DCWhat LDA #XCTLCODE ; Control/status code no good
JSR SysErr ; Return to SOS with error in A
DCFormat
;
; Write Block0, Block1 to disk
;
LDX SOS_Unit ; Get the stats on this unit
LDY DCB_Idx,X
LDA DIB0_Blks,Y
STA VolBlks ; Fill VolBlks with capacity
LDA DIB0_Blks+1,Y
STA VolBlks+1
LDA #$00
STA VolBlks+2
STA shBlockNumber
STA shBlockNumber+1
STA shBlockNumber+2
STA shBlockNumber+3
JSR ZeroFillC800
LDA CFFAUnit ; Get the unit number we're talking about
STA shUnitNumber
LDA #kCmd3K_Write
JSR CFFA3K_API
BCS Error
INC shBlockNumber
LDA #kCmd3K_Write
JSR CFFA3K_API
BCS Error
JSR FormatFill
JSR Catalog ; Write Directory information to the disk
RTS
Error SEC
JSR SysErr ; Return to SOS with error in A
;------------------------------------
;
; Utility routines
;
;------------------------------------
;
; Read_Block - Read requested blocks from device into memory
;
Read_Block
LDA SosBuf ; Copy out buffer pointers
STA DataBuf
LDA SosBuf+1
STA DataBuf+1
LDA SosBuf+ExtPG
STA DataBuf+ExtPG
LDA CFFAUnit
STA shUnitNumber ; Now we have the CFFA3000 unit
LDA SosBlk
STA shBlockNumber
LDA SosBlk+1
STA shBlockNumber+1
LDA #$00
STA shBlockNumber+2
STA shBlockNumber+3
Read3k LDA #kCmd3K_Read
JSR CFFA3K_API
BCC @1 ; Branch past error
STA LastError
CMP #XDISKSW
BNE @0
JSR ZeroUnit
JSR UnitInit ; Re-initialize this unit
JMP Dispatch ; Go around again!
@0 LDA LastError
JSR SysErr ; Return to SOS with error in A
@1 LDA #$00
STA C800Ptr
LDA #$C8
STA C800Ptr+1 ; Establish a pointer to C800
LDY #$00
@2 LDA (C800Ptr),Y
STA (DataBuf),Y
INY
BNE @2
JSR IncrAdr
@3 LDA (C800Ptr),Y
STA (DataBuf),Y
INY
BNE @3
JSR IncrAdr
DEC Num_Blks ; Did we get what was asked for?
BNE RdBlk2
DEC Num_Blks+1
BPL RdBlk2
CLC
RTS
RdBlk2 INC shBlockNumber ; 16-bit increment of block number
BNE Read3k
INC shBlockNumber+1
JMP Read3k
;
; Write_Block - write memory out to requested blocks
;
Write_Block
LDA SosBuf ; Copy out buffer pointers
STA DataBuf
LDA SosBuf+1
STA DataBuf+1
LDA SosBuf+ExtPG
STA DataBuf+ExtPG
LDA SOS_Unit
STA shUnitNumber
CLC
INC shUnitNumber ; Now we have the CFFA3000 unit
LDA SosBlk
STA shBlockNumber
LDA SosBlk+1
STA shBlockNumber+1
LDA #$00
STA shBlockNumber+2
STA shBlockNumber+3
Write3k LDA #$00
TAY
STA C800Ptr
LDA #$C8
STA C800Ptr+1 ; Establish a pointer to C800
@2 LDA (DataBuf),Y
STA (C800Ptr),Y
INY
BNE @2
JSR IncrAdr
@3 LDA (DataBuf),Y
STA (C800Ptr),Y
INY
BNE @3
LDA #kCmd3K_Write
JSR CFFA3K_API
BCC @1 ; Branch past error
STA LastError
CMP #XDISKSW
BNE @0
JSR ZeroUnit
JSR UnitInit ; Re-initialize this unit
JMP Dispatch ; Go around again!
@0 LDA LastError
JSR SysErr ; Return to SOS with error in A
@1 JSR IncrAdr
DEC Num_Blks ; Did we put what was asked for?
BNE WrBlk2 ; Not done yet... go around again
DEC Num_Blks+1 ; (16 bit decrement)
BPL WrBlk2 ; Not done yet... go around again
CLC
RTS ; We're done
WrBlk2 INC shBlockNumber ; 16-bit increment of block number
BNE Write3k
INC shBlockNumber+1
JMP Write3k
;
; ZeroUnit - clear out the capacity bytes of this unit
;
ZeroUnit LDX SOS_Unit
LDY DCB_Idx,X
LDA #$00
STA DIB0_Blks,Y
STA DIB0_Blks+1,Y
RTS
;
; Check ReqCnt to ensure it's a multiple of 512.
;
CkCnt LDA ReqCnt ; Look at the lsb of bytes requested
BNE @1 ; No good! lsb should be 00
STA Num_Blks+1 ; Zero out the high byte of blocks
LDA ReqCnt+1 ; Look at the msb
LSR A ; Put bottom bit into carry, 0 into top
STA Num_Blks ; Convert bytes to number of blks to xfer
BCC CvtBlk ; Carry is set from LSR to mark error.
@1 LDA #XBYTECNT
JSR SysErr ; Return to SOS with error in A
;
; Test for valid block number; abort on error
;
CvtBlk LDX SOS_Unit
LDY DCB_Idx,X
SEC
LDA DIB0_Blks+1,Y ; Blocks on unit msb
SBC SosBlk+1 ; User requested block number msb
BVS BlkErr ; Not enough blocks on device for request
BEQ @1 ; Equal msb; check lsb.
RTS ; Greater msb; we're ok.
@1 LDA DIB0_Blks,Y ; Blocks on unit lsb
SBC SosBlk ; User requested block number lsb
BVS BlkErr ; Not enough blocks on device for request
RTS ; Equal or greater msb; we're ok.
BlkErr LDA #XBLKNUM
JSR SysErr ; Return to SOS with error in A
IncrAdr INC C800Ptr+1 ; Increment buffer MSB from CFFA3000
INC Count+1 ; Increment byte count MSB
BumpAdr INC DataBuf+1 ; Increment DataBuf MSB in userland
;
; Fix up the buffer pointer to correct for addressing
; anomalies. We just need to do the initial checking
; for two cases:
; 00xx bank N -> 80xx bank N-1
; 20xx bank 8F if N was 0
; FDxx bank N -> 7Dxx bank N+1
; If pointer is adjusted, return with carry set
;
FixUp LDA DataBuf+1 ; Look at msb
BEQ @1 ; That's one!
CMP #$FD ; Is it the other one?
BCS @2 ; Yep. fix it!
RTS ; Pointer unchanged, return carry clear.
@1 LDA #$80 ; 00xx -> 80xx
STA DataBuf+1
DEC DataBuf+ExtPG ; Bank N -> band N-1
LDA DataBuf+ExtPG ; See if it was bank 0
CMP #$7F ; (80) before the DEC.
BNE @3 ; Nope! all fixed.
LDA #$20 ; If it was, change both
STA DataBuf+1 ; Msb of address and
LDA #$8F
STA DataBuf+ExtPG ; Bank number for bank 8F
RTS ; Return carry set
@2 AND #$7F ; Strip off high bit
STA DataBuf+1 ; FDxx ->7Dxx
INC DataBuf+ExtPG ; Bank N -> bank N+1
@3 RTS ; Return carry set
CkUnit LDA SOS_Unit ; Checks for unit below unit max
CMP MaxUnits
BMI UnitOk
NoUnit LDA #$11 ; Report no unit to SOS
JSR SysErr
UnitOk CLC
RTS
;
; Prepare BitMap and Link blocks for writing to disk
; Part of formatting support
;
FormatFill
LDA #$05 ; Block 5 on Disk
STA shBlockNumber
STA Storage ; Length of DirTbl
JSR ZeroFillC800
LLink LDX Storage
LDA DirTbl,X ; Move Directory Link values into Buffer
STA $C802 ; Store next Directory block #
DEX
LDA DirTbl,X ; Fetch another # from DirTbl
STA $C800 ; Store previous Directory block #
DEX
STX Storage
LDA #kCmd3K_Write
JSR CFFA3K_API ; Write Directory Link values to disk
LDec DEC shBlockNumber ; Decrement MLI block number
LDA shBlockNumber ; See if MLIBlk = 2
CMP #$02
BNE LLink ; Process another Link block
;
; Calculate BitMap Size and cndo
; Part of formatting support
;
BlkCount ; Fill full pages first, then remainder
LDA #$06 ; First block to deal with: $06
STA shBlockNumber
CLC
LDA VolBlks+1
STA FullPages
LDA VolBlks+2
BEQ @1
SEC
@1 ROR FullPages ; VolBlks is now divided by 512
LSR FullPages ; ... by 1024
LSR FullPages ; ... by 2048
LSR FullPages ; ... by 4096
BEQ LastBlock ; No full blocks? Skip to remainder part.
JSR FFFillC800 ; Set up to fill pages with $FFs
LDA #kCmd3K_Write
JSR CFFA3K_API
LDA #$00
STA BlkCnt
STA $C800 ; Mark first blocks as used
STA $C801
LDA #$03
STA $C802
@2
LDA #kCmd3K_Write
JSR CFFA3K_API ; Write Buffer BitMap to block on the disk
LDA #$FF ; Mark first blocks as unused again
STA $C800
STA $C801
STA $C802
INC shBlockNumber
INC BlkCnt
LDA BlkCnt
CMP FullPages
BNE @2
LastBlock
JSR BlkRemainder
LDA #kCmd3K_Write
JSR CFFA3K_API
RTS
BlkRemainder
JSR ZeroFillC800
LDA VolBlks+1 ; Where # of blocks are stored
LDX VolBlks
LDY #$00
STX Storage+1 ; Divide the # of blocks by 8 for bitmap
LSR A ; calculation
ROR Storage+1
LSR A
ROR Storage+1
LSR A
ROR Storage+1
STA Storage+2
BitMapCode
LDA FullPages ; Only tick off 7 blocks if
BNE BitMapNotFirst ; this is the only page in the BAM
LDA #$01 ; Clear first 7 blocks (i.e. %00000001)
STA (C800Ptr),Y
JMP BitMapGo
BitMapNotFirst
LDA #$FF
STA (C800Ptr),Y
BitMapGo
LDY Storage+1 ; Original low block count value
BNE Jump11 ; If it is 0 then make FF
DEY ; Make FF
DEC Storage+2 ; Make 256 blocks less one
STY Storage+1 ; Make FF new low block value
Jump11 LDX Storage+2 ; High Block Value
BNE Jump15 ; If it isn't equal to 0 then branch
LDY Storage+1
JMP Jump19
Jump15 LDA #$C9 ; Set the address of the upper part of
STA C800Ptr+1 ; Block in bitmap being created
LDA #$FF
LDY Storage+1 ; Using the low byte count
Jump20 DEY
STA (C800Ptr),Y ; Store them
BEQ Jump17
JMP Jump20
Jump17 DEY ; Fill in first part of block
LDA #$C8
STA C800Ptr+1
Jump19
LDA #$FF
DEY
STA (C800Ptr),Y
CPY #$01 ; Except the first byte.
BEQ Jump18
JMP Jump19
Jump18 RTS
BlkCnt .BYTE $00
;
; Catalog - Build a Directory Track
; Part of formatting support
;
Catalog CLC
LDA #$06
ADC FullPages
STA shBlockNumber
LDA #kCmd3K_Write
JSR CFFA3K_API ; Write Buffer (BitMap) to block #6
JSR ZeroFillC800
LDY #$2A ; Move Block2 information to $C800
CLoop LDA Block2,Y
STA (C800Ptr),Y
DEY
BPL CLoop
LDA #$02 ; Write block #2 to the disk
STA shBlockNumber
LDA #kCmd3K_Write
JSR CFFA3K_API
RTS
;
; FillC800: clear buffer at $C800
;
FFFillC800
LDA #$FF
PHA
JMP FillC800Go
ZeroFillC800
LDA #$00
PHA
FillC800Go
LDA #$C8
STA C800Ptr+1
LDA #$00
STA C800Ptr
TAY
LDX #$01 ; Loop twice... 512 bytes
PLA
FillLoop
STA (C800Ptr),Y
INY
BNE FillLoop
INC C800Ptr+1
DEX
BPL FillLoop
LDA #$C8
STA C800Ptr+1
LDA #$00
STA C800Ptr
RTS
;
; Formatter Variable Storage Area
;
VolBlks .BYTE $00, $00, $00 ; Number of blocks available
DirTbl .BYTE $02, $04, $03 ; Linked list for directory blocks
.BYTE $05, $04, $00
BitTbl .BYTE $7f ; '01111111' ; BitMap mask for bad blocks
.BYTE $bf ; '10111111'
.BYTE $df ; '11011111'
.BYTE $ef ; '11101111'
.BYTE $f7 ; '11110111'
.BYTE $fb ; '11111011'
.BYTE $fd ; '11111101'
.BYTE $fe ; '11111110'
Storage .BYTE $00, $00, $00 ; General purpose counter/storage byte
Pointer .BYTE $00, $00 ; Storage for track count (8 blocks/track)
Track .BYTE $00, $00 ; Track number being FORMATted
Sector .BYTE $00, $00 ; Current sector number (max=16)
SlotF .BYTE $00, $00 ; Slot/Drive of device to FORMAT
TRKcur .BYTE $00, $00 ; Current track position
TRKdes .BYTE $00, $00 ; Destination track position
TRKbeg .BYTE $00 ; Starting track number
TRKend .BYTE $35 ; Ending track number
FullPages
.BYTE $00 ; Number of BAM pages to fill
DevIndex .BYTE $00 ; Space for index into DEVICES table
Util .BYTE $00
Block2 .BYTE $00, $00, $03, $00 ; Image of block 2 - for $42 bytes
VolLen .BYTE $F5 ; $F0 + length of Volume Name
Volnam .BYTE "BLANK " ; Volume Name
Reserved .BYTE $00, $00, $00, $00, $00, $00
UpLowCase
.BYTE $00, $00
Datime .BYTE $00, $00, $00, $00
Version .BYTE $01
.BYTE $00, $C3, $27, $0D
.BYTE $00, $00, $06, $00
.ENDPROC
.END