init: move.w $dff01c,oldintena
move.w $dff01e,oldintreq
bset #7,oldintena
bset #7,oldintreq
move.w #$7fff,$dff09a ; interrupts aus.
move.w #$7fff,$dff09c ;
;****************************************************************
lea $dff000,a6
lea buffer(pc),a0
lea mfmbuffer,a2
move.l #$4200,d0
move.l #$59,d1
move.l #$0,d2
move.b #$0,d5
jsr TRACKLOADER
;****************************************************************
move.w oldintena(pc),$dff09a
move.w oldintreq(pc),$dff09c
moveq #0,d0
rts
oldintena: dc.w 0
oldintreq: dc.w 0
buffer: blk.b 130000,0
mfmbuffer: blk.w 6400,0
; ============================================================================
; HARDWARE-DISKLOADER (c) ALPHA ONE 2005 (MULTIDRIVE VERSION)
; ***************************************************************************
; IMPROVED TO READ FROM ODD BYTEPOSITIONS.
; PRO VERSION -> WITH TRACKCOUNTER.
;
; ADDITIONS AND CHANGES BY SCENEX
; ***************************************************************************
; – MULTI DRIVE SUPPORT (DF0-DF3)
; – SWITCHING OFF DRIVE MOTORS AFTER TRACKLOADING
; – DELAY OF 500 MS BEFORE CHECKING DSKRDY FLAG
; – TURNING OFF MOTORS WHEN DSKRDY CHECK FAILED AND RETURNING TO CALLER
;
; IN: A6=$DFF000
; A2=MFMBUFFER.L
; A0=BUFFER.L
;
; D0=LENGTH.L
; D1=TRACKNR.L
; D2=BYTEOFFSET.L
; D5=DISKDRIVE.B
TRACKLOADER: LEA $BFD100,A4 ;DRIVESELECT REGISTER
LEA $BFE001,A5 ;DRIVESTATUS REGISTER
AND.L #$FF,D5 ;CLEAR D5 EXCEPT FIRST BYTE
LEA DRIVENUMBER(PC),A1 ;STORE DRIVENUMBER
MOVE.B D5,(A1) ;
MOVE.B D5,D3
ADD.B #3,D3
LEA DRIVEBIT(PC),A1 ;STORE DRIVEBIT
MOVE.B D3,(A1) ;
BSET D3,(A4) ;SET BIT DRIVENUMBER
ANDI.B #$7F,(A4) ;TURN ON MOTOR
BCLR D3,(A4) ;TURN ON MOTOR ON GIVEN DRIVE
BSR DELAYLONG
BTST #5,(A5) ;CHECK FOR DISK READY
BEQ PROCEED ;
BSR STOPDRIVE ;DISK NOT READY – RETURN
RTS ;
PROCEED: LEA CURRENTTRACK(PC),A3
ADD.B D5,D5 ;MULTIPLY BY 2 BECAUSE 2 BYTES
ADDA.W D5,A3 ;ADD OFFSET TO CURRENTTRACK
MOVEQ #0,D7 ;D7 = BYTECOUNTER
ADD.L D2,D0 ;BYTES TO READ + BYTEOFFSET
MOVE.L D0,D3
DIVS.W #$1600,D3
SWAP D3
TST.W D3
BNE.B NORMAL
SWAP D3
SUBQ.B #1,D3
BRA.B CHECKER
NORMAL: SWAP D3
CHECKER: MOVE.B D3,1(A3)
CMP.B #$FF,(A3)
BNE.B MOVETOCYLINDER
MOVE.B #0,(A3)
BSET #1,(A4) ;CHOSE DIRECTION TOWARDS 0
MOVETOZERO: BTST #4,(A5) ;HEAD ON CYLINDER 0?
BEQ.B MOVETOCYLINDER
BSR.W MOVEHEAD ;MOVE HEAD + DELAY
BRA.B MOVETOZERO
MOVETOCYLINDER: BSET #2,(A4) ;CHOOSE HEAD HIGH
BTST #0,D1 ;EVEN OR ODD TRACK?
BEQ.B HEADOK ;TRACK IS EVEN – ALRIGHT!
BCLR #2,(A4) ;CHOOSE HEAD LOW
HEADOK: MOVEQ #0,D3
MOVEQ #0,D5
MOVE.B D1,D3 ;NEW TRACKNUM -> D3
MOVE.B (A3),D5 ;CURRENT TRACK -> D5
MOVE.B D1,(A3) ;REPLACE CURRENT TRACK
LSR.W #1,D3 ;GET CYLINDER NUM NEW TRACK
LSR.W #1,D5 ;GET CYLINDER NUM CUR TRACK
SUB.W D3,D5
BEQ.B READTRACK
BMI.B OTHERDIRECTION
BSET #1,(A4) ;CHOOSE DIRECTION TOWARDS 0
BRA.B CHOSEN
OTHERDIRECTION: BCLR #1,(A4) ;CHOOSE DIRECTION OUTWARDS 0
NEG.W D5
CHOSEN: BSR.W MOVEHEAD
SUBQ.B #1,D5
BNE.B CHOSEN
READTRACK: BSR.W DISKREADY ;EINEN TRACK LESEN
MOVE.W #$8210,$96(A6) ;DMACON
MOVE.W #$7F00,$9E(A6) ;ADKCON
MOVE.W #$8500,$9E(A6) ;ADKCON
MOVE.W #$4489,$7E(A6) ;DSKSYNC
MOVE.W #$4000,$24(A6) ;DSKLEN
MOVE.L A2,$20(A6) ;DSKPTH
MOVE.W #$9900,$24(A6) ;DSKLEN
MOVE.W #$9900,$24(A6) ;DSKLEN
MOVE.W #$2,$9C(A6) ;INTREQ
TRACKREADY: BTST #1,$DFF01F
BEQ.B TRACKREADY
MOVE.W #$4000,$24(A6)
MOVEQ #0,D5 ;DECODE TRACK
DECODE: MOVE.L A2,A1 ;============
MOVE.L #$55555555,D4
FINDSYNC: CMP.W #$4489,(A1)+
BNE.B FINDSYNC
CMP.W #$4489,(A1)
BEQ.B FINDSYNC
MOVE.L (A1),D3
MOVE.L 4(A1),D1
AND.L D4,D3
AND.L D4,D1
ASL.L #1,D3
OR.L D1,D3
ROR.L #8,D3
CMP.B D5,D3
BEQ.B SECTORFOUND
ADD.L #1086,A1 ;$43E MFM SECTOR LENGTH
BRA.B FINDSYNC
SECTORFOUND: ADD.L #56,A1
MOVE.L #(512/4)-1,D6
DECODESECTOR: MOVE.L 512(A1),D1
MOVE.L (A1)+,D3
AND.L D4,D3
AND.L D4,D1
ASL.L #1,D3
OR.L D1,D3
LEA STORE(PC),A3
MOVE.L D3,(A3)
MOVEQ #4-1,D3
LOOP: CMP.L D7,D0
BEQ.B READREADY
CMP.L D7,D2
BGT.B BELOW
MOVE.B (A3),(A0)+
BELOW: ADDQ.L #1,A3
ADDQ.L #1,D7
DBF D3,LOOP
DBF D6,DECODESECTOR
ADDQ.B #1,D5
CMP.B #11,D5
BNE.W DECODE
TRACKDONE: CMP.L D7,D0 ;TRACK DONE, GET ONTO NEXT.
BEQ.B READREADY ;==========================
BTST #2,(A4)
BEQ.B ONTONEXT
BCLR #2,(A4)
BSR.W DELAYSHORT
BRA.W READTRACK
ONTONEXT: BSET #2,(A4)
BSR.W DELAYSHORT
BCLR #1,(A4)
BSR.W MOVEHEAD
BRA.W READTRACK
READREADY: MOVEM.L D6/A0,-(A7)
LEA DRIVENUMBER(PC),A0
MOVEQ #0,D6
MOVE.B (A0),D6
ADD.B D6,D6
BSR STOPDRIVE
LEA CURRENTTRACK(PC),A3
ADDA.W D6,A3
MOVEM.L (A7)+,D6/A0
MOVE.B 1(A3),D0
ADD.B D0,(A3)
RTS
STOPDRIVE: MOVEM.L D0/D6/A0,-(A7)
LEA DRIVEBIT(PC),A0
MOVE.B (A0),D6
MOVE.B #$80,D0
BSET D6,D0
ORI.B D0,(A4)
MOVE.B #$FF,D0
BCLR D6,D0
ANDI.B D0,(A4)
MOVE.B #0,D0
BSET D6,D0
ORI.B D0,(A4)
MOVEM.L (A7)+,D0/D6/A0
RTS
DELAYSHORT: CLR.B $300(A4) ;BFD400 CIAB TIMER A LOW BYTE (TALO)
MOVE.B #$19,$400(A4) ;BFD500 CIAB TIMER A HIGH BYTE (TAHI)
MOVE.B #$1,$D00(A4) ;BFDE00 CIAB CONTROL REGISTER A (CRA)
WAITSHORT: BTST #0,$C00(A4) ;BFDD00 CIAB INTERRUPT CONTROL REGISTER (ICR)
BEQ.B WAITSHORT
BCLR #0,$D00(A4) ;BFDE00 CIAB CONTROL REGISTER A (CRA)
RTS
DELAYLONG: MOVEQ #$6,D6
DELAYLONGLOOP: CLR.B $300(A4) ;BFD400 CIAB TIMER A LOW BYTE (TALO)
MOVE.B #$FF,$400(A4) ;BFD500 CIAB TIMER A HIGH BYTE (TAHI)
MOVE.B #$1,$D00(A4) ;BFDE00 CIAB CONTROL REGISTER A (CRA)
WAITLONG: BTST #0,$C00(A4) ;BFDD00 CIAB INTERRUPT CONTROL REGISTER (ICR)
BEQ.B WAITLONG
BCLR #0,$D00(A4) ;BFDE00 CIAB CONTROL REGISTER A (CRA)
DBF D6,DELAYLONGLOOP
RTS
DISKREADY: BTST #5,(A5) ;WAIT FOR DISK-READY
BNE.B DISKREADY ;===================
RTS
MOVEHEAD: BCLR #0,(A4)
BSR.W DELAYSHORT
BSET #0,(A4)
BSR.W DELAYSHORT
RTS
CURRENTTRACK: DC.B $FF,0,$FF,0,$FF,0,$FF,0
STORE: DC.L 0
DRIVENUMBER: DC.B 0
DRIVEBIT DC.B 0
TRACKLOADERENDE:
; ============================================================================
Good to know Mr.Spiv, thanks for the information.
Could imagine that many loaders back in the time did not consider this “detail” and therefore led to different sorts of hangs.. About what percentage of disk drives are we talking here?
I have no idea.. Must have not been too common. My friend had an external drive with this issue -> got me aware of it quite early. I recall some later a1200s had the same?
Ok thanks Mr.Spiv, so I’ll maybe soon try to rewrite it to take this issue into consideration 🙂
I’ll have soon one kinky loader commented in tutorials, which uses this mechanism. (nb. “soon” to be considered with care, my last soon took 8 years 😉
Nice 😉 Btw, there were disk drives around that never set DSKRDY but were perfectly usable. For those you just need to wait for 500ms and proceed. I did check for disk presence by stepping the head and then checking DSKCHANGE. Afair that was more reliable.