mirror of
https://github.com/david-schmidt/a3DriverDepot.git
synced 2024-06-08 09:29:29 +00:00
1328 lines
51 KiB
ArmAsm
1328 lines
51 KiB
ArmAsm
;CF140A
|
|
; .TITLE "Apple /// CompactFlash/IDE Driver Ver 1.40A"
|
|
;Limit Maximum Volume Size to 32767 Blocks
|
|
|
|
; .PROC CFIDE
|
|
;
|
|
; SOS Equates
|
|
;
|
|
ExtPG = $1401 ;driver extended bank address offset
|
|
AllocSIR = $1913 ;allocate system internal resource
|
|
SELC800 = $1922 ;Enable Expansion Rom Space
|
|
DeAlcSIR = $1916 ;de-allocate system internal resource
|
|
SysErr = $1928 ;report error to system
|
|
EReg = $FFDF ;environment register
|
|
ReqCode = $C0 ;request code
|
|
SOS_Unit = $C1 ;unit number
|
|
SosBuf = $C2 ;SOS buffer pointer
|
|
ReqCnt = $C4 ;requested byte count
|
|
CtlStat = $C2 ;control/status code
|
|
CSList = $C3 ;control/status list pointer
|
|
SosBlk = $C6 ;starting block number
|
|
QtyRead = $C8 ;bytes read return by D_READ
|
|
;
|
|
; Our temps in zero page
|
|
;
|
|
CurPart = $CC ;1 byte
|
|
Count = $CD ;2 bytes
|
|
Validate = $CE ;1 byte
|
|
;
|
|
; Parameter block specific to current SOS request
|
|
;
|
|
ATA_Cmd = $CF
|
|
Drv_Parm = $D0
|
|
Sect_HB = $D1
|
|
Sect_MB = $D2
|
|
Sect_LB = $D3
|
|
Num_Blks = $D4 ;2 bytes lb,hb
|
|
DataBuf = $D6 ;2 bytes
|
|
CurDrive = $D8 ;Current IDE drive number of SOS_Unit #
|
|
CurDrvNo = $DA ;Current DIB drive number of SOS_Unit #
|
|
;
|
|
; SOS Error Codes
|
|
;
|
|
XREQCODE = $20 ;Invalid request code
|
|
XCTLCODE = $21 ;Invalid control/status code
|
|
XCTLPARAM = $22 ;Invalid control/status parameter
|
|
XNORESRC = $25 ;Resource 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
|
|
XDCMDERR = $31 ;device command ABORTED error occurred
|
|
XCKDEVER = $32 ;Check device readiness routine failed
|
|
XNORESET = $33 ;Device reset failed
|
|
XNODEVIC = $38 ;Device not connected
|
|
;
|
|
; IFC I/O locations
|
|
;
|
|
IFC_ID = $C820
|
|
IOBase = $C080
|
|
ATdataHB = IOBase+$00
|
|
SetCSMsk = IOBase+$01 ;Two special strobe locations to set and
|
|
;clear MASK bit that is used to disable
|
|
;CS0 line to the CompactFlash during the
|
|
;CPU read cycles.
|
|
ClrCSMsk = IOBase+$02 ;that occur before every CPU write cycle.
|
|
;The normally innocuous read cycles were
|
|
;causing the SanDisk CF to double
|
|
;increment during sector writes commands.
|
|
Alt_Stat = IOBase+$06 ;when reading (not used)
|
|
ATAdCtrl = IOBase+$06 ;when writing
|
|
ATdataLB = IOBase+$08
|
|
ATAError = IOBase+$09
|
|
Features = IOBase+$09
|
|
ATSectCt = IOBase+$0a
|
|
ATSector = IOBase+$0b ;11=LB,12=MB,13=HB
|
|
ATAHead = IOBase+$0e
|
|
ATCmdReg = IOBase+$0f ;when writing
|
|
ATA_Stat = IOBase+$0f ;when reading
|
|
;
|
|
; ATA/CF Commands Codes
|
|
;
|
|
ATA_XErr = $03
|
|
ATACRead = $20
|
|
ATACWrit = $30
|
|
ATA_Vrfy = $40
|
|
ATA_Frmt = $50
|
|
ATA_Diag = $90
|
|
ATAIdent = $EC
|
|
SetFeatr = $EF
|
|
;
|
|
; Constants for Wait
|
|
;
|
|
Wait5ms = $2a ; 42.
|
|
Wait150ms = $f2 ; 242.
|
|
;
|
|
; Switch Macro
|
|
;
|
|
.MACRO SWITCH index,bounds,adrs_table,noexec
|
|
.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
|
|
rts ; Exit to code
|
|
.ENDIF
|
|
@110:
|
|
.ENDMACRO
|
|
|
|
.SEGMENT "TEXT"
|
|
|
|
;
|
|
; Comment Field of driver
|
|
;
|
|
.WORD $FFFF
|
|
.WORD $53
|
|
.byte "Apple /// CFFA Driver - "
|
|
.byte "written by Dale S. Jackson 8/08"
|
|
.byte ", modified by D Schmenk 8/11"
|
|
|
|
.SEGMENT "DATA"
|
|
|
|
;
|
|
; DIB Values for Map & Drive No.
|
|
;
|
|
; Map No. IDE $0 IDE $1 Map No. IDE $0 IDE $1
|
|
; 0 $00 $01 32 $80 $81
|
|
; 1 $04 $05 33 $84 $85
|
|
; 2 $08 $09 34 $88 $89
|
|
; 3 $0C $0D 35 $8C $8D
|
|
; 4 $10 $11 36 $90 $91
|
|
; 5 $14 $15 37 $94 $95
|
|
; 6 $18 $19 38 $98 $99
|
|
; 7 $1C $1D 39 $9C $9D
|
|
; 8 $20 $21 40 $A0 $A1
|
|
; 9 $24 $25 41 $A4 $A5
|
|
; 10 $28 $29 42 $A8 $A9
|
|
; 11 $2C $2D 43 $AC $AD
|
|
; 12 $30 $31 44 $B0 $B1
|
|
; 13 $34 $35 45 $B4 $B5
|
|
; 14 $38 $39 46 $B8 $B9
|
|
; 15 $3C $3D 47 $BC $BD
|
|
; 16 $40 $41 48 $C0 $C1
|
|
; 17 $44 $45 49 $C4 $C5
|
|
; 18 $48 $49 50 $C8 $C9
|
|
; 19 $4C $4D 51 $CC $CD
|
|
; 20 $50 $51 52 $D0 $D1
|
|
; 21 $54 $55 53 $D4 $D5
|
|
; 22 $58 $59 54 $D8 $D9
|
|
; 23 $5C $5D 55 $DC $DD
|
|
; 24 $60 $61 56 $E0 $E1
|
|
; 25 $64 $65 57 $E4 $E5
|
|
; 26 $68 $69 58 $E8 $E9
|
|
; 27 $6C $6D 59 $EC $ED
|
|
; 28 $70 $71 60 $F0 $F1
|
|
; 29 $74 $75 61 $F4 $F5
|
|
; 30 $78 $79 62 $F8 $F9
|
|
; 31 $7C $7D 63 $FC $FD
|
|
|
|
;------------------------------------
|
|
;
|
|
; Device identification Block (DIB) - Volume #0
|
|
;
|
|
;------------------------------------
|
|
|
|
DIB_0: .WORD DIB_1 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE1 ";device name
|
|
; .BYTE 0C0 ;active, page aligned
|
|
.BYTE $80 ;active, no page alignment
|
|
DIB0_Slot:
|
|
.BYTE $FF ;slot number
|
|
.BYTE $00 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB0_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD 0003 ;DCB length followed by DCB
|
|
Driv_No0: .BYTE $00 ;Drive #, Bit 0=$0 (master) or $1 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
Part_No0: .BYTE $00 ;Partition number on the drive = $00-07
|
|
FastXfer: .BYTE $00 ;Fast transfer flag
|
|
;
|
|
; Device identification Block (DIB) - Volume #1
|
|
; Page alignment begins here
|
|
;
|
|
DIB_1: .WORD DIB_2 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE2 ";device name
|
|
.BYTE $80 ;active
|
|
.BYTE $FF ;slot number
|
|
.BYTE $01 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB1_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD $0002 ;DCB length followed by DCB
|
|
.BYTE $00 ;Drive # = $00 (master) or $01 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
.BYTE $01 ;Partition number on the drive = $00-07
|
|
;
|
|
; Device identification Block (DIB) - Volume #2
|
|
;
|
|
DIB_2: .WORD DIB_3 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE3 ";device name
|
|
.BYTE $80 ;active
|
|
.BYTE $FF ;slot number
|
|
.BYTE 002 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB2_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD $0002 ;DCB length followed by DCB
|
|
.BYTE $00 ;Drive # = $00 (master) or $01 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
.BYTE 002 ;Partition number on the drive = $00-07
|
|
;
|
|
; Device identification Block (DIB) - Volume #3
|
|
;
|
|
DIB_3: .WORD DIB_4 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE4 ";device name
|
|
.BYTE $80 ;active
|
|
.BYTE $FF ;slot number
|
|
.BYTE 003 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB3_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD $0002 ;DCB length followed by DCB
|
|
.BYTE $00 ;Drive # = $00 (master) or $01 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
.BYTE 003 ;Partition number on the drive = $00-07
|
|
;
|
|
; Device identification Block (DIB) - Volume #4
|
|
;
|
|
DIB_4: .WORD DIB_5 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE5 ";device name
|
|
.BYTE $80 ;active
|
|
.BYTE $FF ;slot number
|
|
.BYTE 004 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB4_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD $0002 ;DCB length followed by DCB
|
|
.BYTE $00 ;Drive # = $00 (master) or $01 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
.BYTE 004 ;Partition number on the drive = $00-07
|
|
;
|
|
; Device identification Block (DIB) - Volume #5
|
|
;
|
|
DIB_5: .WORD DIB_6 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE6 ";device name
|
|
.BYTE $80 ;active
|
|
.BYTE $FF ;slot number
|
|
.BYTE 005 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB5_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD $0002 ;DCB length followed by DCB
|
|
.BYTE $00 ;Drive # = $00 (master) or $01 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
.BYTE 005 ;Partition number on the drive = $00-07
|
|
;
|
|
; Device identification Block (DIB) - Volume #6
|
|
;
|
|
DIB_6: .WORD DIB_7 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE7 ";device name
|
|
.BYTE $80 ;active
|
|
.BYTE $FF ;slot number
|
|
.BYTE $06 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB6_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD $0002 ;DCB length followed by DCB
|
|
.BYTE $00 ;Drive # = $00 (master) or $01 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
.BYTE $06 ;Partition number on the drive = $00-07
|
|
;
|
|
; Device identification Block (DIB) - Volume #7
|
|
;
|
|
DIB_7: .WORD $0000 ;link pointer
|
|
.WORD Entry ;entry pointer
|
|
.BYTE 7 ;name length byte
|
|
.byte ".CFIDE8 ";device name
|
|
.BYTE $80 ;active
|
|
.BYTE $FF ;slot number
|
|
.BYTE $07 ;unit number
|
|
.BYTE $D1 ;type
|
|
.BYTE $10 ;subtype
|
|
.BYTE $00 ;filler
|
|
DIB7_Blks:
|
|
.WORD $0000 ;# blocks in device
|
|
.WORD $444A ;manufacturer - DJ
|
|
.WORD $140A ;Version 1.40A
|
|
.WORD $0002 ;DCB length followed by DCB
|
|
.BYTE $00 ;Drive # = $00 (master) or $01 (slave)
|
|
;Upper 6 bits = Partition address.
|
|
;64 different partition addresses avail.
|
|
.BYTE $07 ;Partition number on the drive = $00-07
|
|
|
|
|
|
;------------------------------------
|
|
;
|
|
; Local storage locations
|
|
;
|
|
;------------------------------------
|
|
|
|
SlotCX: .BYTE $00 ;compute C0X0 and store on init
|
|
PtBlkIdx: .BYTE $A3,$A8,$B3,$B8,$C3,$C8,$D3,$D8 ;Offsets to 8 block
|
|
PtVolIdx: .BYTE $A6,$AB,$B6,$BB,$C6,$CB,$D6,$DB ;segment for ea partition
|
|
UnitStat: .RES $08,$FF ;if UnitStat,X = $FF then partition info
|
|
;not initialized
|
|
;if UnitStat,X > $0F then UnitStat = error code
|
|
;else UnitStat,X = partition number
|
|
;if UnitStat,0 = #XNODRIVE then driver is
|
|
;nonfunctional
|
|
LastOP: .RES $08,$FF ;last op for D_REPEAT calls
|
|
StBlk_HB: .RES $08,$00 ;Starting block number for SOS/ProDos
|
|
StBlk_MB: .RES $08,$00 ;vol #0, vol #1, vol #2, vol #3
|
|
StBlk_LB: .RES $08,$00 ;vol #4, vol #5, vol #6, vol #7
|
|
Block_LB: .RES $08,$00 ;Total blocks for each volume #
|
|
Block_HB: .RES $08,$00
|
|
DCB_Idx: .BYTE $00
|
|
.BYTE DIB1_Blks-DIB0_Blks
|
|
.BYTE DIB2_Blks-DIB0_Blks
|
|
.BYTE DIB3_Blks-DIB0_Blks
|
|
.BYTE DIB4_Blks-DIB0_Blks
|
|
.BYTE DIB5_Blks-DIB0_Blks
|
|
.BYTE DIB6_Blks-DIB0_Blks
|
|
.BYTE DIB7_Blks-DIB0_Blks
|
|
SIR_Addr: .WORD SIR_Tbl
|
|
SIR_Tbl: .RES $05,$00
|
|
SIR_Len = *-SIR_Tbl
|
|
PmapCall: .RES $03,$00 ;Block $hb mb lb for partition record
|
|
.BYTE $01,$00 ;Read 1 ATA sector (block) lb, hb
|
|
.WORD PmapBuf ;Buffer address to place partition record
|
|
PmapBuf: .RES $0100,$00
|
|
Err_Data: .RES $0100,$00
|
|
RdBlk1Pr: .WORD RdBlk1
|
|
WrBlk1Pr: .WORD WrBlk1
|
|
RdBlk2Pr: .WORD RdBlk2
|
|
WrBlk2Pr: .WORD WrBlk2
|
|
RdBlk_Proc:
|
|
.WORD $0000
|
|
WrBlk_Proc:
|
|
.WORD $0000
|
|
|
|
; .byte "Written By Dale S. Jackson, initial writing 12/12/02"
|
|
; .byte "v1.40a revised 8/20/11 By Dave Schmenk"
|
|
|
|
;------------------------------------
|
|
;
|
|
; Driver request handlers
|
|
;
|
|
;------------------------------------
|
|
|
|
Entry: LDA UnitStat+0
|
|
CMP #XNODEVIC
|
|
BEQ No_Drive
|
|
LDX SOS_Unit ;get drive number for this unit
|
|
LDY DCB_Idx,X
|
|
LDA Driv_No0,Y
|
|
STA CurDrvNo
|
|
AND #$01 ;only bit 0 counts
|
|
STA CurDrive ;Set device to LBA mode
|
|
ORA #$0E ;device mode bits %00001(LBA)1(Drive#)
|
|
ASL A ;shift left 4 bits to high order nibble
|
|
ASL A
|
|
ASL A
|
|
ASL A
|
|
STA Drv_Parm
|
|
LDA ReqCode
|
|
CMP #$02 ;Status Call
|
|
BCS @2
|
|
LDA UnitStat,X ;Check if partition table is current
|
|
CMP #$FF
|
|
BNE @1
|
|
JSR GetPmap ;fetch it if not.
|
|
JSR PInit
|
|
LDX SOS_Unit
|
|
LDA UnitStat,X
|
|
@1: CMP #$10 ;Check if SOS_Unit driver is good.
|
|
BCS Err_Out1
|
|
@2: JSR Dispatch ;Now call the dispatcher
|
|
LDX SOS_Unit ;Save current operation
|
|
LDA ReqCode ;for D_REPEAT processing
|
|
STA LastOP,X
|
|
RTS
|
|
;
|
|
; The Dispatcher. Does it depending on ReqCode. Note
|
|
; that if we came in on a D_INIT call, we do a branch to
|
|
; Dispatch, normally. Dispatch is called as a subroutine!
|
|
; We copy the buffer pointer and block # from the parameter
|
|
; area into our own temps, as the system seems to want them
|
|
; left ALONE.
|
|
;
|
|
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 - invalid request
|
|
.WORD BadOp-1 ;7 close - invalid request
|
|
.WORD DInit-1 ;8 init request
|
|
.WORD DRepeat-1 ;9 repeat request
|
|
Dispatch: SWITCH ReqCode,9,DoTable ;go do it.
|
|
;
|
|
; Errors
|
|
;
|
|
BadReq: LDA #XREQCODE ;bad request code!
|
|
Err_Out1: JSR SysErr ;doesn't return
|
|
Slot_Err: LDA #XNODEVIC ;#XNORESRC SIR not available
|
|
STA UnitStat+0 ;no! it didn't go ok.
|
|
No_Drive: LDA #XNODRIVE ;Flag this driver not useable
|
|
JSR SysErr ;doesn't return
|
|
;
|
|
; D_INIT call processing for all Volumes.
|
|
; Called at system init time only. Check DIB0_Slot to
|
|
; make sure that the user set a valid slot number for our
|
|
; interface. Allocate it by calling AllocSIR. If slot not
|
|
; available then set UnitStat+0 to XNORESRC error code.
|
|
;
|
|
; Compute the system internal resource number (SIR) and
|
|
; call AllocSIR to try and grab that for us. It performs
|
|
; slot checking as a side effect.
|
|
;
|
|
DInit: LDA SIR_Tbl
|
|
BNE Norm_Out
|
|
LDA DIB0_Slot
|
|
AND #$07
|
|
ORA #$10 ;SIR = 16+slot#
|
|
STA SIR_Tbl
|
|
LDA #SIR_Len
|
|
LDX SIR_Addr
|
|
LDY SIR_Addr+1
|
|
JSR AllocSIR ;this one's mine!
|
|
BCS Slot_Err
|
|
LDA DIB0_Slot ;Compute C0X0 for this slot
|
|
ASL A
|
|
ASL A
|
|
ASL A
|
|
ASL A
|
|
STA SlotCX
|
|
JSR ResetIFC ;Initialization of Device
|
|
BCS Slot_Err
|
|
LDY #$07 ;Reset drive status to initial startup
|
|
LDA #$FF
|
|
@1: STA UnitStat,Y
|
|
DEY
|
|
BPL @1
|
|
Norm_Out: CLC
|
|
RTS
|
|
;
|
|
; D_REPEAT - repeat the last D_READ or D_WRITE call
|
|
;
|
|
DRepeat: LDX SOS_Unit
|
|
LDA LastOP,X ;look at the last thing we did
|
|
CMP #$02
|
|
BCS BadOp
|
|
STA ReqCode
|
|
JMP Dispatch
|
|
BadOp: LDA #XBADOP ;invalid operation!
|
|
JSR SysErr ;doesn't return
|
|
;
|
|
; D_READ call processing
|
|
;
|
|
DRead: JSR CkCnt
|
|
LDA #ATACRead
|
|
STA ATA_Cmd
|
|
CRead: LDA #$00 ;Zero # bytes read
|
|
STA Count
|
|
STA Count+1
|
|
TAY
|
|
STA (QtyRead),Y ;bytes read
|
|
INY
|
|
STA (QtyRead),Y ;msb of bytes read
|
|
LDA Num_Blks ;check for Num_Blks greater than zero
|
|
ORA Num_Blks+1
|
|
BEQ ReadExit
|
|
@1: JSR FixUp
|
|
JSR Read_Blk ;Transfer a block to/from the disk
|
|
LDY #$00
|
|
LDA Count
|
|
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
|
|
SRead: JSR Read_Blk ;Transfer a block to/from the disk
|
|
BCC ReadExit
|
|
IO_Error: LDA #XIOERROR ;I/O error
|
|
JSR SysErr ;doesn't return
|
|
;
|
|
; D_WRITE call processing
|
|
;
|
|
DWrite: JSR CkCnt
|
|
LDA #ATACWrit
|
|
STA ATA_Cmd
|
|
CWrite: LDA Num_Blks ;check for Num_Blks greater than zero
|
|
ORA Num_Blks+1
|
|
BEQ WriteExit ;quantity to write is zero
|
|
JSR FixUp
|
|
JSR Write_Blk
|
|
BCS IO_Error
|
|
WriteExit:
|
|
RTS
|
|
;
|
|
; D_STATUS call processing
|
|
; $00 Drivers Status - always $0
|
|
; $01 Return device identification - $0200 bytes long
|
|
; $02 Return most recent device error information/data
|
|
; $03 Return partition table data - $0100 bytes long
|
|
; $04 Return DIB configuration bytes - 2 bytes long
|
|
; $FE Return preferrred bitmap location ($FFFF)
|
|
;
|
|
DStatus: LDA CtlStat ;status command
|
|
BNE @1
|
|
TAY ;Driver Status = $0 always
|
|
STA (CSList),Y
|
|
RTS
|
|
@1: CMP #$01
|
|
BEQ S_Ident
|
|
CMP #$02
|
|
BEQ ErrStat
|
|
CMP #$03
|
|
BEQ ParTable
|
|
CMP #$04
|
|
BEQ DIBinfo
|
|
CMP #$FE
|
|
BEQ BitMap
|
|
CS_Bad: LDA #XCTLCODE ;control/status code no good
|
|
Err_Out3: JSR SysErr ;doesn't return
|
|
ParTable: JSR GetPmap ;Return partn table of current SOS_Unit
|
|
BNE @2 ;Partition map is not valid
|
|
LDY #$00
|
|
@1: LDA PmapBuf,Y
|
|
STA (CSList),Y
|
|
INY
|
|
BNE @1
|
|
RTS
|
|
@2: JMP No_Drive
|
|
ErrStat: LDY #$05 ;Return most recent error data.
|
|
@1: LDA Err_Data,y ; Byte 0: Device Status Code
|
|
STA (CSList),Y ; Byte 1: Device Error Code
|
|
DEY ; (if status ERR bit is 0, error code = 0)
|
|
BPL @1 ; Byte 2,3,4: Sector# (LB,MB,HB) of error
|
|
CLC ; Byte 5: # of sectors left to xfer
|
|
RTS
|
|
DIBinfo: LDX SOS_Unit ;Return DIB configuration bytes
|
|
LDY DCB_Idx,X
|
|
LDA Part_No0,Y ;Get assigned partition number this driver
|
|
PHA
|
|
LDA Driv_No0,Y ;Get assigned partition map/IDE device
|
|
LDY #$00 ;for this driver.
|
|
STA (CSList),Y
|
|
INY
|
|
PLA
|
|
STA (CSList),Y
|
|
CLC
|
|
RTS
|
|
BitMap: LDY #$00 ;Return preferred bit map locations.
|
|
LDA #$FF ;We return FFFF, don't care
|
|
STA (CSList),Y
|
|
INY
|
|
STA (CSList),Y
|
|
CLC
|
|
RTS
|
|
S_Ident: LDA CSList ;Device Identification
|
|
STA DataBuf
|
|
LDA CSList+1
|
|
STA DataBuf+1
|
|
LDA CSList+ExtPG
|
|
STA DataBuf+ExtPG
|
|
LDA #ATAIdent
|
|
STA ATA_Cmd
|
|
C_Ident: LDA #$01
|
|
STA Num_Blks
|
|
LDA #$00
|
|
STA Num_Blks+1
|
|
JMP SRead
|
|
|
|
;
|
|
; D_CONTROL call processing
|
|
; $00 Reset device
|
|
; $01 Perform device I/O function with user supplied
|
|
; call block.
|
|
; $04 Set DIB configuration bytes
|
|
; $FE Perform media formatting
|
|
;
|
|
DControl: LDA CtlStat ;control command
|
|
BEQ CReset
|
|
CMP #$01
|
|
BEQ UserIO
|
|
CMP #$04
|
|
BEQ New_DIB
|
|
CMP #$FE ;formatting?
|
|
BEQ MFormat
|
|
JMP CS_Bad ;Control code no good!
|
|
CReset: JSR ResetIFC ;Reset CFFA card
|
|
BCS @1
|
|
RTS
|
|
@1: LDA #XNORESET
|
|
JSR SysErr ;doesn't return
|
|
MFormat: LDX #$07 ;Execute media formatting call.
|
|
@1: LDY DCB_Idx,X
|
|
LDA Driv_No0,Y
|
|
CMP CurDrvNo
|
|
BNE @2
|
|
LDA #$FF ;Invalidate partition table status
|
|
STA UnitStat,X ;so subsequent read/writes
|
|
@2: DEX ;will re-initialize the partition info
|
|
BPL @1 ;for each driver designated for this
|
|
CLC ;partiton table.
|
|
RTS
|
|
New_DIB: LDX SOS_Unit ;Save new DIB configuration bytes
|
|
LDA #$FF ;Invalidate partition table status of driver
|
|
STA UnitStat,X
|
|
LDY #$00
|
|
LDA (CSList),Y
|
|
PHA
|
|
INY
|
|
LDA (CSList),Y
|
|
LDY DCB_Idx,X
|
|
STA Part_No0,Y ;Get assigned partition number this driver
|
|
PLA
|
|
STA Driv_No0,Y ;Get assigned partition map/IDE device
|
|
CLC ;for this driver.
|
|
RTS
|
|
UserIO: LDY #$04
|
|
@1: LDA (CSList),Y
|
|
STA ATA_Cmd+1,Y
|
|
DEY
|
|
BNE @1
|
|
LDA Num_Blks ;if zero then 256 blocks is requested
|
|
BNE @2
|
|
INY
|
|
@2: STY Num_Blks+1
|
|
CLC ;Setup data addresses
|
|
LDA CSList
|
|
ADC #$05
|
|
STA QtyRead
|
|
LDA CSList+1
|
|
ADC #$00
|
|
STA QtyRead+1
|
|
LDA QtyRead
|
|
ADC #$02
|
|
STA DataBuf
|
|
LDA QtyRead+1
|
|
ADC #$00
|
|
STA DataBuf+1
|
|
LDA CSList+ExtPG
|
|
STA QtyRead+ExtPG
|
|
STA DataBuf+ExtPG
|
|
LDY #$00
|
|
LDA (CSList),Y
|
|
LDY #$06
|
|
@3: CMP CtrlCmds,y
|
|
BEQ @4
|
|
DEY
|
|
BPL @3
|
|
JMP CS_Bad
|
|
@4: STA ATA_Cmd
|
|
TYA
|
|
ASL A
|
|
TAY
|
|
LDA Cmd_Tbl+1,Y
|
|
PHA
|
|
LDA Cmd_Tbl,Y
|
|
PHA
|
|
RTS
|
|
;
|
|
; Perform I/O with user supplied call block
|
|
; Call Block Organization:
|
|
; Byte 0: ATA Command Code
|
|
; Byte 1,2,3: Sector# (HB,MB,LB absolute sector)
|
|
; Byte 4: # of sectors
|
|
; Byte 5-6: Bytes returned to buffer
|
|
; Byte 7... Data Buffer
|
|
;
|
|
CtrlCmds: .BYTE ATA_XErr
|
|
.BYTE ATACRead
|
|
.BYTE ATACWrit
|
|
.BYTE ATA_Vrfy
|
|
.BYTE ATA_Frmt
|
|
.BYTE ATA_Diag
|
|
.BYTE ATAIdent
|
|
|
|
Cmd_Tbl: .WORD Send_Cmd-1 ;Extended Error Info $03
|
|
.WORD CRead-1 ;Sector Read $20
|
|
.WORD CWrite-1 ;Sector Write $30
|
|
.WORD Verify-1 ;Read verify $40
|
|
.WORD CWrite-1 ;Sector Format $50
|
|
.WORD Send_Cmd-1 ;Internal Diagnostic Test $90
|
|
.WORD C_Ident-1 ;Device Identity $EC
|
|
|
|
Send_Cmd: JSR CkDevice
|
|
LDA #$00
|
|
STA ATdataHB,x ;Clear high byte data latch
|
|
LDA ATA_Cmd
|
|
STA ATCmdReg,x ;Issue the ATA command to the drive
|
|
@1: LDA ATA_Stat,x
|
|
BMI @1
|
|
LDA ATAError,x
|
|
LDY #$00
|
|
STA (DataBuf),y
|
|
JMP CSet2Mhz
|
|
;
|
|
; Verify - Verify requested blocks
|
|
;
|
|
Verify: LDA #ATA_Vrfy
|
|
JSR SetupLBA ;Program the device's task file registers
|
|
@1: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI @1
|
|
LSR A
|
|
BCS @2
|
|
JMP Set2Mhz
|
|
@2: JMP Save_Err
|
|
|
|
;------------------------------------
|
|
;
|
|
; Partition Table routines
|
|
;
|
|
;------------------------------------
|
|
|
|
;
|
|
; Get Partition Map from drive
|
|
;
|
|
GetPmap: LDA CurDrvNo
|
|
AND #$FC ;get upper 6 bits of drive number for
|
|
STA PmapCall ;partition address.
|
|
LDY #$06
|
|
@1: LDA PmapCall,Y
|
|
STA Sect_HB,Y
|
|
DEY
|
|
BPL @1
|
|
LDA #$00
|
|
STA DataBuf+ExtPG
|
|
LDA #ATACRead
|
|
STA ATA_Cmd
|
|
JSR SRead
|
|
LDY #$02 ;Compute partition table checksum
|
|
LDA #$A5 ;Carry is initially clear
|
|
@2: EOR PmapBuf,Y
|
|
INY
|
|
ADC PmapBuf,Y
|
|
INY
|
|
BNE @2
|
|
EOR PmapBuf,Y
|
|
STA Validate
|
|
RTS ;Return Validate=$0 if valid partition
|
|
;
|
|
; Initialize partition info for each partition in the current table.
|
|
;
|
|
PInit: LDX #$07
|
|
Next_DIB: LDY DCB_Idx,X
|
|
LDA CurDrvNo
|
|
CMP Driv_No0,Y
|
|
BNE IncDIB_x
|
|
LDA Validate
|
|
BNE Bad_Drv
|
|
LDA Part_No0,Y ;Get assigned partition number for this
|
|
CMP #$08 ;driver.
|
|
BCS Bad_Drv ;Partition number is out of range
|
|
STA CurPart
|
|
JSR GVolParm
|
|
BCS Bad_Drv
|
|
LDY DCB_Idx,X
|
|
LDA Block_HB,X
|
|
STA DIB0_Blks+1,Y
|
|
LDA Block_LB,X
|
|
STA DIB0_Blks,Y
|
|
LDA CurPart
|
|
BPL Good_Drv
|
|
Bad_Drv: LDA #XNODRIVE ;Flag this driver not useable
|
|
Good_Drv: STA UnitStat,X
|
|
IncDIB_x: DEX
|
|
BPL Next_DIB
|
|
RTS
|
|
;
|
|
; Get the volume start block in this partition segment
|
|
;
|
|
GVolParm: LDY CurPart ;Xreg contains DIB unit number
|
|
LDA PtBlkIdx,Y
|
|
TAY
|
|
LDA PmapBuf+2,Y ;Block HB
|
|
CMP #$04 ;Test if beginning track is valid
|
|
BCS @1 ;Nope! Beginning block larger than 16 mb
|
|
ORA PmapCall ;set upper 6 bits for partition address
|
|
STA StBlk_HB,X
|
|
LDA PmapBuf+1,Y ;Block MB
|
|
STA StBlk_MB,X
|
|
ORA PmapBuf+2,Y ;Check if beginning track is zero
|
|
ORA PmapBuf,Y
|
|
BEQ Bad_Vol ;Volume start block can't be zero
|
|
LDA PmapBuf,Y ;Block LB
|
|
STA StBlk_LB,X
|
|
LDY CurPart ;Xreg contains DIB unit number
|
|
LDA PtVolIdx,Y ;Get the volume size
|
|
TAY
|
|
LDA PmapBuf,Y
|
|
STA Block_LB,X
|
|
ORA PmapBuf+1,Y
|
|
BEQ Bad_Vol ;Volume size cannot be zero
|
|
LDA PmapBuf+1,Y
|
|
STA Block_HB,X
|
|
BMI Bad_Vol ;Volume size is greater than 32767 blocks
|
|
CLC
|
|
@1: RTS
|
|
Bad_Vol: SEC
|
|
RTS
|
|
|
|
;------------------------------------
|
|
;
|
|
; Utility routines
|
|
;
|
|
;------------------------------------
|
|
|
|
;
|
|
; Check ReqCnt to insure it's a multiple of 512.
|
|
;
|
|
CkCnt: LDA ReqCnt ;look at the lsb of bytes to do
|
|
BNE @1 ;no good! lsb should be 00
|
|
STA Num_Blks+1 ;zero high byte of number of blocks
|
|
LDA ReqCnt+1 ;look at the msb
|
|
LSR A ;put bottom bit into carry, 0 into top
|
|
STA Num_Blks ;save as number of blocks to transfer
|
|
BCC CvtBlk ;Carry is set from LSR to mark error.
|
|
@1: LDA #XBYTECNT
|
|
JSR SysErr ;doesn't return
|
|
;
|
|
; Test for valid block number. Carry clear on return means
|
|
; no error. Carry set means block number bad. X register
|
|
; contains volume number.
|
|
;
|
|
CvtBlk: LDA SosBuf
|
|
STA DataBuf
|
|
LDA SosBuf+1
|
|
STA DataBuf+1
|
|
LDA SosBuf+ExtPG
|
|
STA DataBuf+ExtPG
|
|
LDY SOS_Unit
|
|
LDA SosBlk
|
|
CMP Block_LB,y
|
|
LDA SosBlk+1
|
|
SBC Block_HB,y
|
|
BCS BlkErr
|
|
LDA SosBlk
|
|
ADC StBlk_LB,y
|
|
STA Sect_LB
|
|
LDA SosBlk+1
|
|
ADC StBlk_MB,y
|
|
STA Sect_MB
|
|
LDA StBlk_HB,y
|
|
ADC #$00
|
|
STA Sect_HB
|
|
RTS
|
|
BlkErr: LDA #XBLKNUM
|
|
JSR SysErr ;doesn't return
|
|
IncrAdr: INC Count+1
|
|
INC Count+1
|
|
BumpAdr: INC DataBuf+1 ;increment DataBuf msb
|
|
;
|
|
; Fix up the buffer pointer to correct for an 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
|
|
;
|
|
; Wait - Copy of Apple's wait routine.
|
|
; Input:
|
|
; A = delay time, where Delay(us) = 2.5A^2 + 13.5A + 36
|
|
; including JSR to this routine.
|
|
; or more typically A = (Delay[in uS]/2.5 - 7.11)^.5 - 2.7
|
|
Wait: PHP
|
|
SEI
|
|
SEC
|
|
@1: PHA
|
|
@2: SBC #$01
|
|
BNE @2
|
|
PLA
|
|
SBC #$01
|
|
BNE @1
|
|
PLP
|
|
RTS
|
|
;
|
|
; Throttle back to 1 MHz
|
|
;
|
|
Set1Mhz: PHP
|
|
SEI
|
|
LDA EReg
|
|
ORA #$80
|
|
STA EReg
|
|
PLP
|
|
RTS
|
|
;
|
|
; Throttle up to 2 MHz
|
|
;
|
|
CSet2Mhz: CLC
|
|
Set2Mhz: PHP
|
|
SEI
|
|
LDA EReg
|
|
AND #$7F
|
|
STA EReg
|
|
PLP
|
|
RTS
|
|
|
|
;----------------------------------
|
|
;
|
|
; Supplemental Device Subroutines
|
|
;
|
|
; Device Internal Diagnostic Routine ATA Command $90
|
|
; Returns 1 byte of diagnostic code in Buffer
|
|
; $01 = No Error Detected
|
|
; $02 = Formatter Device Error
|
|
; $03 = Sector Buffer Error
|
|
; $04 = ECC Circuitry Error
|
|
; $05 = Controlling Microprocessor Error
|
|
; $8x = Slave Failed (true IDE mode)
|
|
;
|
|
; Extended Error Code Request
|
|
; Returns 1 byte of exteded error code in Buffer
|
|
; $00 = No Error Detected
|
|
; $01 = Self test OK (No error)
|
|
; $09 = Miscellaneous Error
|
|
; $20 = Invalid Command
|
|
; $21 = Invalid address (requested head or sector invalid)
|
|
; $2F = Address Overflow (address too large)
|
|
; $35,$36 = Supply voltage out of tolerance
|
|
; $11 = Uncorrectable ECC error
|
|
; $18 = Corrected ECC Error
|
|
; $05,$30-34,$37,$3E = Self test or diagnostic failed
|
|
; $10,$14 = ID not found
|
|
; $3A = Spare sectors exhausted
|
|
; $1F = Data transfer error/Aborted command
|
|
; $0C,$38,$3B,$3C,$3F = Corrupted Media Format
|
|
; $03 = Write/Erase failed
|
|
;
|
|
;----------------------------------
|
|
|
|
;
|
|
; Execute reset call to ATA device
|
|
;
|
|
ResetIFC: JSR Set1Mhz
|
|
LDA RdBlk1Pr
|
|
STA RdBlk_Proc
|
|
LDA RdBlk1Pr+1
|
|
STA RdBlk_Proc+1
|
|
LDA WrBlk1Pr
|
|
STA WrBlk_Proc
|
|
LDA WrBlk1Pr+1
|
|
STA WrBlk_Proc+1
|
|
; LDA DIB0_Slot
|
|
; JSR SELC800 ;Turn on ROM
|
|
; LDA IFC_ID+2
|
|
; AND #0F0 ;Check major ROM version is 2.xx
|
|
; EOR IFC_ID+1
|
|
; EOR IFC_ID
|
|
; TAX
|
|
; LDA #000
|
|
; JSR SELC800 ;Turn off ROM
|
|
; CPX #015
|
|
; BNE No_Ver2
|
|
LDA FastXfer
|
|
BEQ No_Ver2
|
|
LDA RdBlk2Pr
|
|
STA RdBlk_Proc
|
|
LDA RdBlk2Pr+1
|
|
STA RdBlk_Proc+1
|
|
LDA WrBlk2Pr
|
|
STA WrBlk_Proc
|
|
LDA WrBlk2Pr+1
|
|
STA WrBlk_Proc+1
|
|
No_Ver2: LDX SlotCX
|
|
LDA ClrCSMsk,x ;reset MASK bit in PLD for normal CS0
|
|
LDA #$00 ;signaling.
|
|
STA ATdataHB,x ;Clear high byte data latch
|
|
LDA #$06 ;Reset bit=1, Disable INTRQ=1
|
|
STA ATAdCtrl,x
|
|
JSR Norm_Out ;Per ATA-6 spec, need to wait 5us minimum.
|
|
LDA #$02 ;Reset bit=0, Disable INTRQ=1
|
|
STA ATAdCtrl,x
|
|
LDY #$d0 ; 208. ;Per ATA-6 spec, need to wait 2ms minimum
|
|
LDA #Wait5ms ;Use a initial delay of 5ms.
|
|
@1: JSR Wait
|
|
LDA ATA_Stat,x ;Per ATA-6 spec, wait up to 31 sec for
|
|
BMI @2 ;busy to clear if a slave is attached.
|
|
JMP CSet2Mhz
|
|
@2: LDA #Wait150ms ;Wait for up to 31 secs if a slave is
|
|
DEY ;attached. After 31 secs pass, the card
|
|
BNE @1 ;is not installed in slot.
|
|
SEC ;Drive(s) Not Ready
|
|
JMP Set2Mhz
|
|
;
|
|
; Check Device - test drive status register is readable
|
|
; and equal to $40
|
|
;
|
|
CkDevice: JSR Set1Mhz
|
|
LDY #$c8 ;200.
|
|
LDX SlotCX
|
|
LDA ClrCSMsk,x ;reset MASK bit in PLD for normal CS0
|
|
@1: LDA ATA_Stat,x ;signaling.
|
|
BMI @1
|
|
AND #$08 ;%00001000 Check bus can receive a
|
|
BEQ @2 ;device register setting DRQ=0
|
|
LDA #Wait5ms
|
|
JSR Wait ;Wait 5ms to try again
|
|
DEY
|
|
BNE @1 ;Wait up to 1 second for drive to be ready
|
|
BEQ NotReady ;always taken
|
|
@2: LDA Drv_Parm ;Select drive to check
|
|
STA ATAHead,x
|
|
LDY #$c8 ;200.
|
|
@3: LDA ATA_Stat,x
|
|
BMI @3
|
|
AND #$E9 ;%11101001 Check if device is ready to
|
|
CMP #$40 ;receive a command. If BSY=0, RDY=1,
|
|
BNE @4 ;DF=0, DRQ=0, and ERR=0
|
|
RTS ;We're good to go. Returns @ 1 Mhz clock
|
|
;Xreg = SlotCX, and carry set.
|
|
@4: LDA #Wait5ms
|
|
JSR Wait ;Wait 5ms to try again
|
|
DEY
|
|
BNE @3 ;Wait up to 1 seconds for drive readiness
|
|
NotReady: JSR Set2Mhz
|
|
LDA #XCKDEVER ;DEVICE NOT READY error
|
|
JSR SysErr
|
|
;
|
|
; SetupLBA - Programs devices task registers with LBA data
|
|
; Input:
|
|
; partition data Sect_HB, MB, & LB
|
|
; A = command
|
|
; X = requested slot number in form $n0 where
|
|
; n = slot 1 to 7
|
|
; This function programs the device registers with
|
|
; the ATA Logical Block Address (LBA) to be accessed.
|
|
; A SOS block and a ATA sector are both 512 bytes.
|
|
; Logical Block Mode, the Logical Block Address is
|
|
; interpreted as follows:
|
|
; LBA07-LBA00: Sector Number Register D7-D0.
|
|
; LBA15-LBA08: Cylinder Low Register D7-D0.
|
|
; LBA23-LBA16: Cylinder High Register D7-D0.
|
|
; LBA27-LBA24: Drive/Head Register bits HS3-HS0.
|
|
;
|
|
SetupLBA: PHA
|
|
JSR CkDevice ;returns with carry set
|
|
LDA Sect_LB
|
|
STA ATSector,x ;store low block # into LBA 0-7
|
|
LDA Sect_MB
|
|
STA ATSector+1,x ;store mean block # into LBA 15-8
|
|
LDA Sect_HB
|
|
STA ATSector+2,x ;store high block # LBA bits 23-16
|
|
LDA Num_Blks
|
|
STA ATSectCt,x ;store # of blocks to be read/written
|
|
LDA #$00
|
|
STA ATdataHB,x
|
|
TAY
|
|
PLA
|
|
STA ATCmdReg,x ;Issue the command
|
|
RTS
|
|
;
|
|
; Save device error status
|
|
;
|
|
Save_Err: LDA ATA_Stat,x
|
|
STA Err_Data
|
|
LSR A
|
|
BCS @1 ;if status ERR bit is one then get error
|
|
LDA #$00 ;register data,else return error data
|
|
BEQ @2 ;byte = zero.
|
|
@1: LDA ATAError,x
|
|
@2: STA Err_Data+1
|
|
LDA ATSector,x ;retrieve sector # error occurred
|
|
STA Err_Data+2 ;LB
|
|
LDA ATSector+1,x
|
|
STA Err_Data+3 ;MB
|
|
LDA ATSector+2,x
|
|
STA Err_Data+4 ;HB
|
|
LDA ATSectCt,x
|
|
STA Err_Data+5 ;retrieve # of sectors left
|
|
STY Count
|
|
SEC
|
|
JMP Set2Mhz
|
|
;
|
|
; Read_Blk - Read requested blocks from device into memory
|
|
;
|
|
;
|
|
Read_Blk: LDA ATA_Cmd
|
|
JSR SetupLBA ;Program the device's task file registers
|
|
JMP (RdBlk_Proc)
|
|
;
|
|
; CFFA Ver 1.x
|
|
;
|
|
RdBlk1: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI RdBlk1
|
|
AND #$09 ;Check for error response from device
|
|
CMP #$08 ;If DRQ=0 or ERR=1 a device error
|
|
BNE Read_Err
|
|
@1: LDA ATdataLB,x
|
|
STA (DataBuf),y
|
|
INY
|
|
LDA ATdataHB,x
|
|
STA (DataBuf),y
|
|
@2: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI @2
|
|
INY
|
|
BNE @1
|
|
INC DataBuf+1
|
|
@3: LDA ATdataLB,x
|
|
STA (DataBuf),y
|
|
INY
|
|
LDA ATdataHB,x
|
|
STA (DataBuf),y
|
|
@4: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI @4
|
|
INY
|
|
BNE @3
|
|
JSR IncrAdr
|
|
DEC Num_Blks ;did we get what was asked for
|
|
BNE RdBlk1
|
|
DEC Num_Blks+1
|
|
BPL RdBlk1
|
|
JMP CSet2Mhz
|
|
Read_Err: JMP Save_Err
|
|
;
|
|
; CFFA Ver 2.x
|
|
;
|
|
RdBlk2: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI RdBlk2
|
|
AND #$09 ;Check for error response from device
|
|
CMP #$08 ;If DRQ=0 or ERR=1 a device error
|
|
BNE Read_Err
|
|
@1: LDA ATdataLB,x
|
|
STA (DataBuf),y
|
|
INY
|
|
LDA ATdataHB,x
|
|
STA (DataBuf),y
|
|
INY
|
|
BNE @1
|
|
INC DataBuf+1
|
|
@2: LDA ATdataLB,x
|
|
STA (DataBuf),y
|
|
INY
|
|
LDA ATdataHB,x
|
|
STA (DataBuf),y
|
|
INY
|
|
BNE @2
|
|
JSR IncrAdr
|
|
DEC Num_Blks ;did we get what was asked for
|
|
BNE RdBlk2
|
|
DEC Num_Blks+1
|
|
BPL RdBlk2
|
|
JMP CSet2Mhz
|
|
;
|
|
; Write_Blk - write requested blocks to device from memory
|
|
;
|
|
Write_Blk:
|
|
LDA ATA_Cmd
|
|
JSR SetupLBA ;Program the device's task file registers
|
|
JMP (WrBlk_Proc)
|
|
;
|
|
; CFFA Ver 1.x
|
|
;
|
|
WrBlk1: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI WrBlk1
|
|
AND #$09 ;Check for error response from device
|
|
CMP #$01 ;If DRQ=0 and ERR=1 a device error
|
|
BEQ Write_Err
|
|
@1: LDA SetCSMsk,x ;any access sets mask bit to block
|
|
;IDE -CS0 on I/O read to drive
|
|
INY
|
|
LDA (DataBuf),y
|
|
STA ATdataHB,x
|
|
DEY
|
|
LDA (DataBuf),y
|
|
STA ATdataLB,x
|
|
LDA ClrCSMsk,x
|
|
@2: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI @2
|
|
INY
|
|
INY
|
|
BNE @1
|
|
INC DataBuf+1
|
|
@3: LDA SetCSMsk,x
|
|
INY
|
|
LDA (DataBuf),y
|
|
STA ATdataHB,x
|
|
DEY
|
|
LDA (DataBuf),y
|
|
STA ATdataLB,x
|
|
LDA ClrCSMsk,x ;Set back to normal, allow CS0 assertions
|
|
;on read cycles
|
|
@4: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI @4
|
|
INY
|
|
INY
|
|
BNE @3
|
|
JSR BumpAdr
|
|
DEC Num_Blks ;did we do what was asked for
|
|
BNE WrBlk1
|
|
DEC Num_Blks+1 ;we might have to do this one more time
|
|
BPL WrBlk1
|
|
LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
AND #$09 ;Check for error response from device
|
|
CMP #$01 ;If DF=1 or DRQ=0 or ERR=1 a device error
|
|
BEQ Write_Err
|
|
JMP CSet2Mhz ;exit write routines
|
|
Write_Err:
|
|
JMP Save_Err
|
|
;
|
|
; CFFA Ver 2.x
|
|
;
|
|
WrBlk2: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI WrBlk2
|
|
AND #$09 ;Check for error response from device
|
|
CMP #$01 ;If DRQ=0 or ERR=1 a device error
|
|
BEQ Write_Err
|
|
LDA SetCSMsk,x ;any access sets mask bit to block
|
|
;IDE -CS0 on I/O read to drive
|
|
@1: INY
|
|
LDA (DataBuf),y
|
|
STA ATdataHB,x
|
|
DEY
|
|
LDA (DataBuf),y
|
|
STA ATdataLB,x
|
|
INY
|
|
INY
|
|
BNE @1
|
|
INC DataBuf+1
|
|
@2: INY
|
|
LDA (DataBuf),y
|
|
STA ATdataHB,x
|
|
DEY
|
|
LDA (DataBuf),y
|
|
STA ATdataLB,x
|
|
INY
|
|
INY
|
|
BNE @2
|
|
LDA ClrCSMsk,x ;Set back to normal, allow CS0 assertions
|
|
;on read cycles
|
|
JSR BumpAdr
|
|
DEC Num_Blks ;did we do what was asked for
|
|
BNE WrBlk2
|
|
DEC Num_Blks+1 ;we might have to do this one more time
|
|
BPL WrBlk2
|
|
@3: LDA ATA_Stat,x ;Wait for BUSY flag to clear
|
|
BMI @3
|
|
AND #$09 ;Check for error response from device
|
|
CMP #$01 ;If DF=1 or DRQ=0 or ERR=1 a device error
|
|
BEQ Write_Err
|
|
JMP CSet2Mhz ;exit write routines
|