supermario/base/SuperMarioProj.1994-02-09/Drivers/NewAge/NewAgeDrvr.a
2019-06-29 23:17:50 +08:00

4458 lines
175 KiB
Plaintext

;
; File: NewAgeDrvr.a
;
; Contains: This is the driver for the NewAge Floppy Disk Controller.
;
; Written by: Robert Polic
;
; Copyright: © 1992-1993 by Apple Computer, Inc., all rights reserved.
;
; This file is used in these builds:
;
; Change History (most recent first):
;
; <SM23> 6/14/93 kc Roll in Ludwig.
; <LW30> 5/19/93 WS Changed retries to 25, except during disk verification.
; <LW29> 5/1/93 WS Change fifo setting to F. Enable Precom.
; <LW28> 4/30/93 WS Remove a debugger and a debugstr.
; <LW27> 4/22/93 WS Change name of driver to .Sony for compatibility. Removed loops
; to check for successful PSC writes. Changes approved by CCC mal
; and chp.
; <LW26> 4/13/93 WS Changed SetupFDC so that it checks whether it has been call
; since disk insertion. If it has than do nothing. TrackDump
; will now dump from sector 0 if it is call in mode 0 with a GCR
; disk.
; <LW25> 4/5/93 WS Check for negative drive number in DriveStatus and return error.
; <LW24> 4/5/93 WS Call to DriveStatus with drive number 1 or 2 will not return
; with error. The paramblock will be filled out to make it
; compatible with the SWIM driver.
; <LW23> 3/31/93 WS Fixed bug where if a disk is inserted close to a disk eject
; command the floppy drive appears to hang. Updated a error code.
; <LW22> 3/24/93 WS Changed the floppy icon so that it looks like all the other Mac
; floppy icon. Modified error check in SenseInterrupt since
; Newage something return the Equipment Check error bit falsely.
; Changed the close rountine so that in does nothing but return
; closErr for compatiblity. Changed all _BlockMove to
; _BlockMoveData.
; <LW21> 3/18/93 WS Fix the EjectDisk rountine so system does not hang aftera disk
; eject. Reduced some of the time out waits. Added a couple more
; error code to report failures.
; <LW20> 3/16/93 chp Replace references to the obsolete PSCIntTbl lomem with
; references to the equivalent field in ExpandMem.
; <LW19> 3/12/93 WS Add error check for all code that uses the SenseInterruptStatus
; command to Newage.
; <LW18> 3/10/93 WS Fix diskcopy bug
; <LW17> 3/8/93 WS The error code for checking for the correct ioVRefNum was stuff
; in a register which got blow away later. Fixed. Defer some on
; the stuff for a disk insertion interrupt.
; <LW16> 3/1/93 WS Increase some more time out counts.
; <LW15> 3/1/93 WS Increased timeout count for WriteToFDC and ReadFromFDC.
; <LW14> 2/23/93 WS Changed DriveStatus so that it returns -1 instead of just a
; generic negative number in the sides formatted field to indicate
; 2-sided format. Also the interface field will noe return 0 for
; 400K disk to indicated the old interface.
; <LW13> 2/17/93 WS Fixed the calculation of the starting sector so that it works
; for all modes. Bug # 1066659.
; <LW12> 2/16/93 WS Fix bug which cause a DMA bus error when doing a write retry.
; Also added a code to handle a DMA bus error if it occurs.
; <LW11> 2/10/93 WS Roll out changes to return only one formatlist for 800K GCR
; format.
; <LW10> 2/9/93 WS Added code to verify a disk in the diskcopy call to make it
; compatible with Apple tech. note. For 1.44 Meg MFM disk
; Formatlist will now return with bit set in the "current disk has
; this format" field to make it compatible with the old driver and
; to make Diskcopy 4.2 work. Fixes bug # 1062754. Formatlist
; also changed to return only one list for 800K GCR disk. Fies
; bug # 1064306 again.
; <LW9> 1/20/93 WS Added icon for the Tempest machines. Fixed the Icon for
; Cyclone. Added Cyclone40 to Icon Table.
; <LW8> 1/18/93 WS I a generic unformatted disk is inserted into the floppy drive,
; Newage may hang. Added code for Newage to recover if this
; ocurs.
; <LW7> 1/15/93 WS Change the Icon for Cyclone so that it doesn't look like a
; IICi. Tookout most of the debugger breaks. Changed the format
; and format/write gor GCR. It should no be faster and a little
; less buggy.
; <LW6> 1/7/93 WS Undo some of the changes added in SM16. FormatList now will
; return 2 entry for 800k GCR format. One for Macintosh style and
; another for ProDos.
; <LW5> 1/4/93 WS If format disk is called with param of zero, it will default to
; format the disk for most storage given the media and drive type.
; Update and use dCtlposition from the DCtlEntry for offset in
; read and write operations. Check for invalid cylinder number
; and return paramErr if invlaid cylinder is requested.
; <LW4> 12/15/92 WS Added fix to handle error for write protected disk during disk
; format and disk copy.
; <LW3> 12/14/92 WS Update ioActCount correctly.
; <LW2> 12/14/92 WS Removed some code that used to be conditional compiled. Added
; code to handle calls to the floppy driver with interrupt level
; mask at 2 or greater. Bypassed bug where an interrupt occurs
; before the CmdBsy bit in the status register is stable. Added
; check for disk being manually ejected during format and
; terminate format it this is true. Optimized MFM format
; read/write.
; <SM22> 12/9/92 WS Replace some numbers with equates.
; <SM21> 12/9/92 WS Roll out most of the changes from the last checkin because it
; was causing the floppy to hang during accesses.
; <SM20> 11/30/92 WS Added code to reset Newage in timeout occurs during a DMA
; transfer. Check that the CPU interrupt mask is less than 2, if
; not poll the interrupt, other the driver will never know if an
; interrupt occurs. Misc error check per code review.
; <SM19> 11/17/92 WS Add code to read ahead to end of track for all track accesses.
; If this fails then retries will occurs reading only the
; requested tracks. This does not use the READ A TRACK command.
; In fact, the code using the READ A TRACK command have been
; remove since there will be some changes in its inplementation.
; Add code to make multitrack read work with this scheme. The PSC
; count register is now check after every read to make sure the
; requested number of bytes are read. Add code to restore the
; controller to the proper state if a failure occurs while testing
; for ED format disk.
; <SM18> 11/11/92 fau Fixed a bug where the correct result was not being returned
; after a call to the driver.
; <SM17> 11/5/92 WS My system crash while checking in <SM16> I double checked
; everything and am checking it in again. No changes.
; <SM16> 11/5/92 WS Change error check for invalid ioVrefNum so that it does not
; crash. Fixed Format List so that it return only one entry for
; 800K floppies.
; <SM15> 10/22/92 CSS Fixed a branch short to a regular branch as direct calling of
; traps expanded code.
; <SM14> 10/15/92 WS Add code to stripe leading zeroes for the TrackDump routine
; during GCR mode.
; <SM13> 10/8/92 PN Fix DriveInfo to return the correct values
; <SM12> 10/7/92 WS Replaced a lot of hard code number with equates. Added the
; rountine ReadATrack which is not being use yet. It will be use
; when NEC fixes the bugs related to the READ A TRACK command.
; <SM11> 9/24/92 WS Add SenseInterrupt Command in open to remove pending interrupts
; before installing the handler
; <SM10> 9/23/92 WS Read only the tracks that are requested.
; <SM9> 9/15/92 WS Add timeout for wait loops. Disk Copy is now DMA. Track Dump
; is changed back to poll due to technical difficulties.
; <SM8> 8/28/92 WS Trackdump now DMAs data to buffer before sorting it out. Change
; GSL to #$25, so it will sector 36.
; <SM7> 8/28/92 WS Change GSL in read and write command from #$1B to #$24 to bypass
; bug in Newage. Add in format code to Rawdump command. Change
; icons.
; <SM6> 8/13/92 WS Minor cleanup here and there to remove redundant stuff.
; <SM5> 8/12/92 WS Because I am a goof, I failed to add all the commands under
; thsSM4 heading. Eventhough this is the SM5 heading, All these
; command is for SM4. Pause PSC channel after format command. In
; TrackDump routine do 32 byte loops instead of 8 byte loops. The
; clock table for TrackDump have also been updated. In DiskCopy
; rountine add in command to switch in and out of non-DMA mode.
; Check for motor on before sending disk copy command. Now looks
; at the correct location to determind whether command should be
; in MFM or GCR mode. Recalibrate track before exiting Disk Copy.
; Change Gap 3 length to 101 bytes. Shorted timeout loop for Read
; ID command. Clear fMotor flag after ResetFDC call. Fix fCylinder
; so it is not corrupted after Sense Interrupt Status cammand (use
; to get bash after calls other that Seek and REcal). Change fifo
; depth to 8.
; <SM4> 8/12/92 WS check for can't find IDR after read and write before doing a
; seek prior to retry.
; <SM3> 7/28/92 WS Software PSC (FDC channel) before accessing count and address
; registers to flush internal fifo. Set Newage fifo fepth to 3.
; Perform seek trak before each retry.
; <SM2> 7/24/92 RLM changed via2 addr $50f31008 to $50f03a00 and $50f3100c to
; $50f03c00
; <P2> 7/2/92 RMP Added raw track dump. Fixed various other bugs.
; <1> 4/10/92 RMP first checked in
;
; To Do:
;
Break Equ 0
noClose Equ 1
BLANKS ON
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'FSEqu.a'
INCLUDE 'PSCEqu.a'
INCLUDE 'NewAgeEqu.a'
PRINT ON
MACHINE MC68020
MAIN
;------------------------------------------------------------------------------
; Data: Driver header.
;------------------------------------------------------------------------------
DRVR Dc.w $6F00 ; drvrFlags (Inside Mac p II-188).
Dc.w $0014 ; drvrDelay.
Dc.w $0000 ; drvrEMask.
Dc.w $0000 ; drvrMenu.
Dc.w Open - drvr ; Offset to open routine.
Dc.w Prime - drvr ; Offset to prime routine.
Dc.w Control - drvr ; Offset to control routine.
Dc.w Status - drvr ; Offset to status routine.
Dc.w Close - drvr ; Offset to close routine.
;** Dc.w '.NewAge' ; Driver name.
Dc.w '.Sony' ; Driver name. <LW27>
;------------------------------------------------------------------------------
; Routine: Open
; Inputs: A0 -> Parameter block.
; A1 -> DCE.
; Outputs: D0 -> 0 - OK, ~0 - Error.
; Function: Open driver and allocate needed memory. Init the FDC.
;------------------------------------------------------------------------------
WITH FloppyRecord,ExpandMemRec,PSC_INT_TBL
OpenRegs REG A0-A3/D3-D5 ; Registers abused.
Open Movem.l OpenRegs,-(Sp) ; Save registers.
Move.l ioRefNum(A0),D3 ; Save refNum in high word.
Movea.l A1,A3 ; Save DCE.
Move.l A1,NewAgeVars ; Save it.
Clr.l dCtlStorage(A3) ; Assume no drives are installed.
Clr.l dCtlPosition(A3) ; Clear position.
Move.l #NewAge32,A0 ; Base address of NewAge.
Bsr ResetFDC ; Initialize FDC.
Moveq #0,D4 ; Bit number to check.
@InstallLoop Movea.l #NewAge32,A0 ; Base address of NewAge.
Move.b #SetEnableOn,D0 ; Enable drive.
Bsr WriteToFDC ; Send it.
Move.b D4,D0 ; Drive select.
Bsr WriteToFDC ; Enable drive.
Move.b #SenseDrvStatus,D0 ; Sense drive status command.
Bsr WriteToFDC ; Send command.
Move.b D4,D0 ; Drive select.
Bsr WriteToFDC ; Send command.
Bsr ReadFromFDC ; Read Status3.
Move.b D0,D5 ; Save it.
Move.b #SetEnableOff,D0 ; Disable drive.
Bsr WriteToFDC ; Send it.
Move.b D4,D0 ; Drive select.
Bsr WriteToFDC ; Disable drive.
Move.b #SenseIntStatus,D0 ; Sense interrupt status command. <SM11>
Bsr WriteToFDC ; Send command. <SM11>
Bsr ReadFromFDC ; Get Status0. <SM11>
Cmp.b #$FF,D5 ; No drive?
Beq @Next ; No? Then try next drive. <SM15> CSS
Moveq #fRecSize,D0 ; Bytes needed for floppy info record.
_NewPtr ,Sys,Clear ; Allocate local storage.
Movea.l A0,A2 ; For use later.
Move.l dCtlStorage(A3),D0 ; Record already installed?
Bne.s @2 ; Yes? Then link it.
Move.l A2,dCtlStorage(A3) ; Save in DCE.
Bra.s @AddDrive ; Add drive queue element.
@2 Movea.l D0,A0 ; Pointer to first record.
Move.l A2,fNextRecord(A0) ; Link it.
@AddDrive Moveq #20,D0 ; Bytes needed for drive queue elements.
_NewPtr ,Sys,Clear ; Allocate it.
Move.w D4,D3 ; Drive bit (refNum in high word).
Add.w #1,D3 ; Drive number (1 or 2).
Tst.l (A0)+ ; Skip over flags.
Move.w #1,qType(A0) ; Set queue type to drive.
Move.l D3,D0 ; RefNum/DrvNum.
Swap D0 ; DrvNum/RefNum.
_AddDrive ; Add drive to queue.
Move.w D3,fDriveNum(A2) ; Install drive number.
Move.b #RetryCount,fRetrySeed(A2) ; Set seed value.
Move.w #dtQType, DTQE+qType(A2) ; Set Deferred Task queue type
Move.l A0,fDriveQueue(A2) ; Save drive queue pointer.
Move.b D4,fDriveSelect(A2) ; Set drive select.
Move.w #fddMac800,fDriveType(A2) ; Assume 800K.
Btst #fDriveStatus,D5 ; Drive bit clear?
Beq.s @Buffer ; Yes? Then must be 800K.
Move.w #fddSuperDrive,fDriveType(A2) ; Assume SuperDrive.
Btst #fMode,D5 ; Mode bit set?
Bne.s @Buffer ; Yes? Then SuperDrive.
Move.w #fddTyphoon,fDriveType(A2) ; Must be a Typhoon.
@Buffer Move.l #BufferSize*BlockSize,D0 ; Bytes needed. <SM9>
_NewPtr ,Sys,Clear ; Try allocating it.
Move.l A0,fBuffer(A2) ; Save buffer.
Movea.l #BufferSize*BlockSize,A1 ; Bytes needed. <SM9>
_LockMemory ; Lock it.
@Next Addq.w #1,D4 ; Next drive bit.
Cmp.w #2,D4 ; Are we done?
Beq.s @InstallHandler ; Yes? Then leave.
Bra @InstallLoop ; Check next drive.
@InstallHandler Lea Handler,A1 ; Pointer to interrupt handler.
Move.l A1,VIA2DT+FloppyEntry ; Install handler.
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM1> RLM
Movea.l ([ExpandMem],emDMADispatchGlobals), A1 ; A1-> PSC Interrupt table ptr
Lea FDCDMAInt, A2 ; Pointer to interruot handler. <LW12>
Move.l A2, FDChndlr(A1) ; Install DMA bus error handler. <LW12>
@ExitOpen Movem.l (Sp)+,OpenRegs ; Restore registers.
Moveq #noErr,D0 ; Indicate no error.
Move.w D0,ioResult(A0) ; Set result value.
Move.l JIODone,-(Sp) ; Vector to IODone.
Rts ; And call it.
;------------------------------------------------------------------------------
; Routine: Prime
; Inputs: A0 -> Parameter block.
; A1 -> DCE.
; Outputs: D0 -> 0 - OK, ~0 - Error.
; Function: Handle read/write requests.
;------------------------------------------------------------------------------
PrimeRegs REG A0-A5/D3-D7 ; Registers abused.
Prime Movem.l PrimeRegs,-(Sp) ; Scratch registers.
Movea.l NewAgeVars,A3 ; DCE pointer.
Movea.l A0,A4 ; Save parameter block.
Movea.l ioBuffer(A4),A2 ; Buffer.
Movea.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Move.w ioDrvNum(A4),D0 ; Drive number.
Cmp.w fDriveNum(A1),D0 ; Correct record?
Beq.s @Prepare ; Yes? Then use it.
Movea.l fNextRecord(A1),A1 ; Next record.
Beq.s @0 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Correct record? <SM16>
Beq.s @Prepare ; Yes? Then use it. <SM16>
@0 Movea.l dCtlStorage(A3),A1 ; Give it a real floppy info. <SM16>
Move.w #nsDrvErr,fResult(A1); Assume no such drive. <LW17>
Bra.s @ExitPrime ; Out of here <SM16>
@Prepare Move.w #offLinErr,fResult(A1) ; Assume no disk.
Tst.w fMediaType(A1) ; Disk in?
Beq.s @ExitPrime ; No? Then leave.
Move.b fRetrySeed(A1),fRetries(A1) ; Reset retry count.
Move.w #paramErr,fResult(A1) ; Assume Parameter Error. <LW5>
Move.l dCtlPosition(A3),D1 ; Assume I/O from mark. <LW5>
@Offset Move.l D1,fPosition(A1) ; New mark.
Blt.s @ParamErr ; Error if call with negative sector. <LW5>
Asr.l #8,D1 ; Get starting sector…
Asr.l #1,D1 ; …by dividing by 512.
Move.l D1,D5 ; Save start.
Clr.l ioActCount(A4) ; Init actual count.
Move.l ioReqCount(A4),D4 ; Bytes to I/O.
Asr.l #8,D4 ; Get number of sectors…
Asr.l #1,D4 ; …by dividing by 512.
Cmpi.b #aRdCmd,ioTrap+1(A4); Read call?
Beq.s @DoRead ; Yes? Then call read routine.
Bsr DoWrite ; No? Then call write routine.
Bra.s @ExitPrime ; Leave.
@DoRead Bsr DoRead ; Call read routine.
@ExitPrime Movea.l NewAgeVars,A3 ; DCE pointer.
Move.l fPosition(A1),dCtlPosition(A3); Update. <LW5>
@ParamErr Move.l Ticks,fLastAccess(A1) ; Update time.
Move.w fResult(A1),D1 ; Call result.
@Exit Movem.l (Sp)+,PrimeRegs ; Restore registers.
Move.w D1,ioResult(A0) ; Set result value.
Move.w ioTrap(A0),D1 ; Trap called.
Btst #noQueueBit,D1 ; Called immediately?
Bne.s @2 ; Yes? Then leave via an RTS.
Move.w ioResult(A0),D0 ; Check for our result and return it in D0
Ble.s @1 ; Yes? Then go through IODone.
Btst #asyncTrpBit,D1 ; Called asynchronously?
Bne.s @2 ; Yes? Then leave via an RTS.
@1 Move.l JIODone,-(Sp) ; Vector to IODone.
@2 Rts ; Return.
;------------------------------------------------------------------------------
; Routine: DoRead
; Inputs: A1 -> Floppy info record.
; A2 -> User buffer.
; A4 -> Parameter block.
; D4 -> Count in sectors.
; D5 -> Start (in sectors).
; Outputs: fResult(A1).
; Function: Handle read requests.
; Called by: Prime
;------------------------------------------------------------------------------
; At this point, we want to read any data we can out of the DMA buffer (fBuffer).
;
; | fBuffer |
; +------------------------------------+
; |Start (D5) Length (D4) | |
; +--------------------------------------+
; .........BBBBBBBBBBBBBBBBBBBBBBBBBBBBBfffffffffff
;
; . - Offset into buffer
; B - Read from buffer
; f - Read from floppy
;
; If the start (D5) is less than the start of the buffer (fStart), all data will
; be read from the floppy.
;
DoRead Moveq #0,D7 ; Set flag that FDC is not setup.
Move.w #noErr,fResult(A1) ; In case there are no sectors to read.
Cmp.w #rdVerify,ioPosMode(A4) ; Read verify?
Blt.s @CheckBuffer ; No? Then check if data is in buffer.
Clr.w fCount(A1) ; Clear buffer to force read from media.
Bra.s @ReadLoop ; Read it.
@CheckBuffer Move.w fCount(A1),D0 ; Is buffer empty?
Beq.s @ReadLoop ; Yes? Then read from media.
Move.w fStart(A1),D1 ; Starting sector of buffer.
Cmp.w D1,D5 ; Is data in buffer?
Blt.s @ReadLoop ; No? Then read from media.
Add.w D1,D0 ; Ending sector in buffer.
Sub.w D5,D0 ; Is there an intersection?
Bmi.s @ReadLoop ; No? Then read from media.
Sub.w D5,D1 ; Offset (negative).
Neg.w D1 ; Force positive.
Sub.w D0,D4 ; Sectors remaining after read from buffer.
Bpl.s @CopyFromBuffer ; Copy from buffer.
Add.w D4,D0 ; Blocks needed.
Moveq #0,D4 ; Set remaining count to 0.
@CopyFromBuffer Move.l A1,A3 ; Save floppy info record.
Add.w D0,D5 ; Bump up starting block.
Move.l fBuffer(A3),A0 ; Pointer to buffer.
Ext.l D1 ; Force long.
Asl.l #8,D1 ; Calculate offset…
Asl.l #1,D1 ; By multiplying by 512.
Add.l D1,A0 ; Offset into buffer.
Move.l A2,A1 ; User buffer.
Ext.l D0 ; Force to long.
Asl.l #8,D0 ; Multiply by 512…
Asl.w #1,D0 ; …to get number of bytes.
Move.l D0,ioActCount(A4) ; Update “actual” count.
Add.l D0,A2 ; Update user buffer pointer.
_BlockMoveData ; Copy into buffer.
Move.l A3,A1 ; Floppy info record.
; At this point, we have read everything we could from the DMA buffer and the following
; registers have been updated:
; ioActCount reflects then number of bytes read from the buffer.
; Application buffer pointer has been bumped up by number of bytes read.
; The starting sector (D5) has been bumped up by number of sectors read.
; The count has been decremented by number of sectors read.
;
; We will now calculate our physical offsets into the media to do actual read. This is
; also the start of the read loop.
;
@ReadLoop Tst.w D4 ; Are there any blocks left to transfer?
Ble @ExitRead ; No? Then we're done. <SM10>
Tst.l D7 ; FDC setup?
Bmi.s @MFM ; Yes? Then check for MFM read.
Moveq #-1,D7 ; Set flag that FDC is setup.
Bsr SetUpFDC ; Set it up.
Tst.w fResult(A1) ; Any errors?
Bne @ExitRead ; Yes? Out of here.
Move.w #sectNFerr,fResult(A1) ; Assume blank disk.
Cmp.w #fBlank,fFormat(A1) ; Blank or missing disk?
Ble @ExitRead ; Yes? Then leave with error.
@MFM Move.w #1,D7 ; Assume side 1.
Moveq #18,D0 ; Min. sectors/cylinder for non-GCR.
Move.w fFormat(A1),D1 ; Format code.
Sub.b #f720K,D1 ; GCR format?
Blt.s @GCR ; Yes? Then variable sectors/cylinder.
Asl.w D1,D0 ; Calc. sectors/cylinder.
Move.l D5,D3 ; Sector for I/O.
Divu D0,D3 ; Find starting track.
Swap D3 ; Sector in low word.
Lea SectorsSide,A5 ; Sectors/side table.
Move.w fFormat(A1),D1 ; Format byte.
Asl.w #1,D1 ; Word index.
Move.w 0(A5,D1.w),D1 ; Sectors/side.
Move.w D1,D6 ; Sector per track.
Swap D6 ; Save it.
Move.w D1,D6 ; Sector per track.
Sub.w D1,D3 ; Subtract number per side from start.
Bpl.s @Seek ; Positive? Then indeed side 1.
Add.w D1,D3 ; Negative? Then side 0.
Clr.w D7 ; Set “head 0” flag.
Bra.s @Seek ; Seek to track.
@GCR Moveq #0,D3 ; Init track register.
Moveq #4,D0 ; Speedzone loop register.
Move.l D5,D1 ; Sector number.
Lea GCR1Side,A5 ; 1-sided GCR lookup table.
Cmp.w #f400K,fFormat(A1) ; 400K format?
Beq.s @0 ; Yes? Then use 1-sided table.
Lea GCR2Side,A5 ; 2-sided GCR lookup table.
@0 Sub.w itSectors(A5),D1 ; Number of sectors in speed zone.
Bmi.s @1 ; Negative? Then we've gone to far.
Tst.w (A5)+ ; Next zone.
Add.w #GCRCylndrs,D3 ; Add cylinders.
Dbra D0,@0 ; Loop.
@1 Add.w itSectors(A5),D1 ; Make positive.
Divu (A5),D1 ; Divide by number of sectors in zone.
Add.w D1,D3 ; Add in cylinder number.
Swap D3 ; Cylinder number in high word.
Swap D1 ; Sector number in low word.
Move.w D1,D3 ; Install sector number.
Moveq #13,D1 ; Start with 13 sectors/side.
Move.l D3,D2 ; Cylinder:Sector.
Swap D2 ; Cylinder in bottom word.
@2 Subq.w #1,D1 ; Bump down sectors/side.
Sub.w #GCRCylndrs,D2 ; Subtract speed zone.
Bpl.s @2 ; +? Then must be in another zone.
Move.w D1,D6 ; Sectors per track.
Swap D6 ; Save it.
Move.w D1,D6 ; Sector per track.
Sub.w D1,D3 ; Subtract number per side from start.
Bpl.s @Seek ; Positive? Then indeed side 1.
Add.w D1,D3 ; Negative? Then side 0.
Clr.w D7 ; Set “head 0” flag.
@Seek Move.l #NewAge32,A0 ; Base address.
Sub.w D3,D6 ; Sectors left on cyclinder (if on side 1).
Swap D3 ; Cylinder in low word.
Move.w #paramErr,fResult(A1) ; Assume Parameter error. <LW5>
Cmp.b #DiskCylndrs,D3 ; Number of cylinders per disk. <LW5>
Bge @ExitRead ; Access beyond last track? <LW5>
Cmp.b fCylinder(A1),D3 ; Drive already at this track?
Beq.s @PrepareBuffer ; Yes? Then skip seek.
Move.w D3,D2 ; Cylinder number.
Bsr SeekToTrack ; Seek to it.
Tst.w fResult(A1) ; Seek error? <LW18>
Bne @ExitRead ; If so report it. <LW18>
; D3.l - Cylinder number.
; D3.h - Starting sector number (physical) (0 based).
; D4 - Number of sectors to be read.
; D5 - Starting sector (logical).
; D6.l - Remaining sectors from start (D3.h) to end-of-track.
; D6.h - EOT.
; D7 - Side (0 or 1).
;
; Examples: MFM 720K D3.h=5, D7=0 then D6=4 (9 sectors/side)
; MFM 1.4M D3.h=2, D7=1 then D6=16 (18 sectors/side)
; GCR 800K D3.l=16 D3.h=5, D7=0 then D6=6 (11 sectors/track for cylinder 16)
; GCR 800K D3.l=32 D3.h=5, D7=0 then D6=5 (10 sectors/track for cylinder 32)
; GCR 400K D3.l=16 D3.h=5, D7=0 then D6=6 (single sided).
;
@PrepareBuffer Move.w D5,fStart(A1) ; Save starting sector.
IF MTMode THEN
Tst.w D7 ; Side 1?
Bne.s @3 ; Yes? Then don't add in side 1 sectors.
Cmp.w #f400K,fFormat(A1) ; Single-sided?
Beq.s @3 ; Yes? Then can't add in side 1.
Move.l D3,D1 ; Sector:Cylinder. <SM19>
Swap D1 ; Starting sectors number. <SM19>
Add.w D4,D1 ; # of sectors to read from start of track <SM19>
Move.l D6,D0 ; EOT. <SM19>
Swap D0 ; Sectors/side. <SM19>
Sub.w D0,D1 ; <SM19>
Sub.w D0,D1 ; <SM19>
Blt.s @3 ; Reading 2 track of data? <SM19>
Add.w D0,D6 ; Total sectors to read. <SM19>
@3
ENDIF
Sub.w D6,D4 ; Subtract off what we can do in one read.
Bpl.s @30 ; Positive? Then copy buffer. <SM10>
Add.w D4,D6 ; Number of sectors to read. <SM10>
@30 Add.w D6,D5 ; Next starting sector.
Move.w D6,fCount(A1) ; Save number of sectors we have read.
;;;;;;;;;;;;;;;;Add to optimize read routine <SM12>
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR?
Ble.s @DoGCR ; Yes? Go do GCR stuff.
Moveq #0,D0 ; Clear D0 for read.
@DoFastMFM Bsr MFMTrack ;
Bra.s @DoCleanUp ;
@DoGCR Bsr ReadAGCRTrack ;
@DoCleanUp Cmp.b #0,D0 ; Check for error.
Bne @20 ; Error? Then go save error and retry.
Move.l D6,D1 ; Get Sector per track.
Swap D1 ; In high word.
Move.l D3,D0 ; Get starting sector.
Swap D0 ; In high word.
Sub.w D0,D1 ;
Move.w D1,fCount(A1) ; New count.
Bra @CopyBuffer ;
;;;;;;;;;;;;;;;; End of addittion <SM12>
@SendCommand Move.b #ReadData,D0 ; Setup read command.
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR?
Bgt.s @4 ; No? Then leave FM bit.
Bclr #fFM,D0 ; Clear FM bit.
IF MTMode THEN
Cmp.w #f400K,fFormat(A1) ; Single-sided?
Bne.s @4 ; No? Then leave multi-track.
Bclr #fMT,D0 ; Clear multi-track.
ENDIF
@4
IF MTMode THEN
Move.l D6,D1 ; EOT. <SM19>
Swap D1 ; EOT. <SM19>
Cmp.b D1,D6 ; Reading more than one track? <SM19>
Bgt.s @11 ; No? Then leave multi-track. <SM19>
Bclr #fMT,D0 ; Clear multi-track. <SM19>
ENDIF
@11 Bsr WriteToFDC ; Send command.
Move.b D7,D0 ; Head select.
Lsl.b #fHd,D0 ; Move into position.
Or.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Write head/drive.
Move.w D3,D0 ; Cylinder/Sector.
Bsr WriteToFDC ; Write cylinder number.
Move.b D7,D0 ; Head.
Bsr WriteToFDC ; Write head number.
Move.l D3,D0 ; Sector:Cyclinder.
Swap D0 ; Sector in low word.
Moveq #-1,D2 ; Assume GCR.
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR format?
Ble.s @5 ; Yes? Then sectors are 0 based.
Addq.b #1,D0 ; Force sector number to be 1 based.
Moveq #0,D2
@5 Bsr WriteToFDC ; Write sector number.
Move.b fCode(A1),D0 ; Format byte (512 bytes/sector).
Bsr WriteToFDC ; Write format byte.
Move.l D3,D0 ; Sector:Cyclinder. <SM10>
Swap D0 ; Starting sector. <SM10>
Add.b D6,D0 ; Number of sectors to read. <SM10>
IF MTMode THEN
Move.l D6,D1 ; Get sector info. <SM19>
Swap D1 ; Get sector per track. <SM19>
Cmp.b D1,D0 ; Reading more than one track? <SM19>
Ble.s @12 ; Yes? EOT. <SM19>
Sub.w D1,D0 ; Multi-track not used. Number of sector to read.<SM19>
@12
ENDIF
@13 Add.b D2,D0 ; 0 or 1 based flag.
Bsr WriteToFDC ; Last sector to read.
Moveq #GSL,D0 ; Gap 3 length. <SM8>
Bsr WriteToFDC ; Write gap length.
Move.w D6,D2 ; Number of sectors to read.
@14 Ext.l D2 ; Force long.
Asl.w #8,D2 ; Multiply by 512.
Asl.w #1,D2
Move.l #pscControl32,A3 ; PSC control register.
Move.w #(1 << pscPause) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause PSC.
@waitfrozen Move.w (A3), D0 ; <SM3>
Btst.l #pscFrozen, D0 ; <SM3>
Beq.s @waitfrozen ; check for pause <SM3>
Move.w (A3),D0 ; Control setting.
And.w #$1,D0 ; Get set.
Asl.w #4,D0 ; Calculate offset to correct set.
Move.l #pscSet032,A5 ; DMA register set.
Move.l fBuffer(A1),pscAddress(A5,D0.w) ; Set address.
Move.l D2,pscCount(A5,D0.w) ; Set count.
Move.w #(1 << pscDir) | \ ;
(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to read and enable.
Move.w #(1 << pscPause) | \ ;
(0 << pscSense), \ ;
(A3) ; Un-pause.
Move.w #1,fResult(A1) ; Set result to “in progress”.
Moveq #0,D0 ; DTL (no special sector size).
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Write DTL.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #2,D1 ; DBRA/4 Millisecond.
@Wait Bsr GetResult ; Check for interrupt. <SM23>
Cmp.w #0,fResult(A1) ; Result.
Ble.s @DoneDMA ; Done? Out of here.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
If Break Then
_debugger
EndIf
Bsr ResetFDC ; If timeout then something horrible happened. <SM20>
Bsr SetupFDC ; Everything needs to be reset. <SM20>
Move.w #noNybErr,fResult(A1); Report as timeout error. <SM20>
@DoneDMA Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w #(1 << pscSWReset) | \ ;
(1 << pscSense), \ ;
(A3) ; Reset channel. <SM19>
Move.w fResult(A1),D0 ; Result.
Beq.s @CopyBuffer ; No error? Then transfer to user buffer.
@20 Move.l fError2(A1),fError3(A1)
Move.l fError2+4(A1),fError3+4(A1)
Move.l fError1(A1),fError2(A1)
Move.l fError1+4(A1),fError2+4(A1)
Move.l fStatus0(A1),fError1(A1)
Move.l fStatus0+4(A1),fError1+4(A1)
Subq.b #1,fRetries(A1) ; Decrement retry counter.
Bgt @SendCommand ; More retries left? Then try again.
Bmi.s @Fail ; Did we recalibrate?
Bsr Track0 ; No? Then try recalibrating.
Tst.w fResult(A1) ; Error?
Bne.s @Fail ; Yes? then fail. <LW18>
Move.w D3,D2 ; Cylinder number.
Bsr SeekToTrack ; Seek to it.
Tst.w fResult(A1) ; Error?.
Bne.s @Fail ; Yes? then fail. <LW18>
Bra @SendCommand ; And try one more time.
@Fail Addq.w #1,fHardErrors(A1) ; Bump hard error counter.
Clr.w fCount(A1) ; Void buffer.
Bra.s @ExitRead ; And leave.
@CopyBuffer Move.l A1,A3 ; Save floppy info record.
Move.l fBuffer(A1),A0 ; Buffer pointer.
Move.l A2,A1 ; Destination.
Move.w D6,D0 ; Number of sectors read. <SM10>
Ext.l D0 ; Force long.
Asl.w #8,D0 ; Multiply by 512.
Asl.w #1,D0
Add.l D0,A2 ; Bump buffer.
Add.l D0,ioActCount(A4) ; Bump actual count.
Cmpa.l A0,A1 ; Let's speed up format verifies.
Beq.s @9
Cmp.w #rdVerify,ioPosMode(A4) ; Read verify?
Blt.s @8 ; No? Then copy into users buffer.
Exg A1,A3 ; Swap registers.
Asr.w #2,D0 ; Long words to compare.
Move.w #dataVerErr,fResult(A1) ; Assume error.
@CompareLoop Cmp.l (A0)+,(A3)+ ; Match?
Bne.s @ExitRead ; Fail? Then leave.
Subq.l #1,D0 ; Decrement counter.
Bne.s @CompareLoop ; Compare till done.
Move.w #noErr,fResult(A1) ; Set no error.
Bra.s @10 ; Continue.
@8 _BlockMoveData ; Transfer into user buffer.
@9 Move.l A3,A1 ; Floppy info record.
@10 Move.b fRetrySeed(A1),D0 ; Initial seed value.
Cmp.b fRetries(A1),D0 ; Did we have to perform a retry?
Beq @ReadLoop ;
Addq.w #1,fSoftErrors(A1) ; Yes? Then bump soft errors.
Move.b D0,fRetries(A1) ; Reset counter.
Bra @ReadLoop
@ExitRead Move.l ioActCount(A4),D0 ; Bytes read.
Add.l D0,fPosition(A1) ; Update position.
Move.l fPosition(A1),ioPosOffset(A4) ; Update position offset.
Rts ; Return.
;------------------------------------------------------------------------------
; Routine: DoWrite
; Inputs: A1 -> Floppy info record.
; A2 -> User buffer.
; A4 -> Parameter block.
; D4 -> Count in sectors.
; D5 -> Start (in sectors).
; Outputs: fResult(A1).
; Function: Handle write requests.
; Called by: Prime
;------------------------------------------------------------------------------
DoWrite Moveq #0,D7 ; Set flag that FDC is not setup.
Move.w #noErr,fResult(A1) ; In case there are no sectors to write.
@WriteLoop Tst.w D4 ; Are there any blocks left to transfer?
Ble @ExitWrite ; No? Then we're done.
Tst.l D7 ; FDC setup?
Bmi.s @MFM ; Yes? Then check for MFM write.
Moveq #-1,D7 ; Set flag that FDC is setup.
Bsr SetUpFDC ; Set it up.
Tst.w fResult(A1) ; Any errors?
Bne @ExitWrite ; Yes? Out of here.
Move.w #sectNFerr,fResult(A1) ; Assume blank disk.
Cmp.w #fBlank,fFormat(A1) ; Blank or missing disk?
Ble @ExitWrite ; Yes? Then leave with error.
@MFM Move.w #1,D7 ; Assume side 1.
Moveq #18,D0 ; Min. sectors/cylinder for non-GCR.
Move.w fFormat(A1),D1 ; Format code.
Sub.b #f720K,D1 ; GCR format?
Blt.s @GCR ; Yes? Then variable sectors/cylinder.
Asl.w D1,D0 ; Calc. sectors/cylinder.
Move.l D5,D3 ; Sector for I/O.
Divu D0,D3 ; Find starting track.
Swap D3 ; Sector in low word.
Lea SectorsSide,A5 ; Sectors/side table.
Move.w fFormat(A1),D1 ; Format byte.
Asl.w #1,D1 ; Word index.
Move.w 0(A5,D1.w),D1 ; Sectors/side.
Move.w D1,D6 ; Sector per track.
Swap D6 ; Save it.
Move.w D1,D6 ; Sector per track.
Sub.w D1,D3 ; Subtract number per side from start.
Bpl.s @Seek ; Positive? Then indeed side 1.
Add.w D1,D3 ; Negative? Then side 0.
Clr.w D7 ; Set “head 0” flag.
Bra.s @Seek ; Seek to track.
@GCR Moveq #0,D3 ; Init track register.
Moveq #4,D0 ; Speedzone loop register.
Move.l D5,D1 ; Sector number.
Lea GCR1Side,A5 ; 1-sided GCR lookup table.
Cmp.w #f400K,fFormat(A1) ; 400K format?
Beq.s @0 ; Yes? Then use 1-sided table.
Lea GCR2Side,A5 ; 2-sided GCR lookup table.
@0 Sub.w itSectors(A5),D1 ; Number of sectors in speed zone.
Bmi.s @1 ; Negative? Then we've gone to far.
Tst.w (A5)+ ; Next zone.
Add.w #GCRCylndrs,D3 ; Add cylinders.
Dbra D0,@0 ; Loop.
@1 Add.w itSectors(A5),D1 ; Make positive.
Divu (A5),D1 ; Divide by number of sectors in zone.
Add.w D1,D3 ; Add in cylinder number.
Swap D3 ; Cylinder number in high word.
Swap D1 ; Sector number in low word.
Move.w D1,D3 ; Install sector number.
Moveq #13,D1 ; Start with 13 sectors/side.
Move.l D3,D2 ; Cylinder:Sector.
Swap D2 ; Cylinder in bottom word.
@2 Subq.w #1,D1 ; Bump down sectors/side.
Sub.w #GCRCylndrs,D2 ; Subtract speed zone.
Bpl.s @2 ; +? Then must be in another zone.
Move.w D1,D6 ; Sectors per track.
Swap D6 ; Save it.
Move.w D1,D6 ; Sector per track.
Sub.w D1,D3 ; Subtract number per side from start.
Bpl.s @Seek ; Positive? Then indeed side 1.
Add.w D1,D3 ; Negative? Then side 0.
Clr.w D7 ; Set “head 0” flag.
@Seek Move.l #NewAge32,A0 ; Base address.
Sub.w D3,D6 ; Sectors left on cyclinder (if on side 1).
Swap D3 ; Cylinder in low word.
Move.w #paramErr,fResult(A1) ; Assume Parameter error. <LW5>
Cmp.b #DiskCylndrs,D3 ; Number of cylinders per disk. <LW5>
Bge @ExitWrite ; Access beyond last track? <LW5>
Cmp.b fCylinder(A1),D3 ; Drive already at this track?
Beq.s @PrepareBuffer ; Yes? Then skip seek.
Move.w D3,D2 ; Cylinder number.
Bsr SeekToTrack ; Seek to it.
Tst.w fResult(A1) ; Seek error? <LW18>
Bne @ExitWrite ; If so report it. <LW18>
; D3.l - Cylinder number.
; D3.h - Starting sector number (physical) (0 based).
; D4 - Number of sectors to be write.
; D5 - Starting sector (logical).
; D6 - Remaining sectors from start (D3.h) to end-of-track.
; D7 - Side (0 or 1).
;
; Examples: MFM 720K D3.h=5, D7=0 then D6=4 (9 sectors/side)
; MFM 1.4M D3.h=2, D7=1 then D6=16 (18 sectors/side)
; GCR 800K D3.l=16 D3.h=5, D7=0 then D6=6 (11 sectors/track for cylinder 16)
; GCR 800K D3.l=32 D3.h=5, D7=0 then D6=5 (10 sectors/track for cylinder 32)
; GCR 400K D3.l=16 D3.h=5, D7=0 then D6=6 (single sided).
;
@PrepareBuffer Move.w D5,fStart(A1) ; Save starting sector.
Sub.w D6,D4 ; Subtract off what we can do in one write.
Bpl.s @3 ; Positive? Then copy buffer.
Add.w D4,D6 ; Number of sectors to write.
@3 Add.w D6,D5 ; Next starting sector.
Move.w D6,fCount(A1) ; Save number of sectors we have read.
Move.l A2,A5 ; Assume we'll use application buffer.
Move.w D6,D0 ; Number of sectors to write.
Ext.l D0 ; Force long.
Asl.w #8,D0 ; Multiply by 512.
Asl.w #1,D0
Add.l D0,A2 ; Bump application buffer.
Move.l A5,A0 ; No? Then copy into DMA buffer.
Move.l A1,A3 ; Save floppy info record.
Move.l fBuffer(A1),A1 ; Buffer pointer.
_BlockMoveData ; Transfer into user buffer.
; Move.l A1,A5 ; Use DMA buffer.
Move.l A3,A1 ; Restore floppy info record.
Move.l #NewAge32,A0 ; Base address.
;;;;;;;;;;;;;;;;Add to optimize read routine <SM12>
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR?
Ble.s @SendCommand ; Yes? Go do GCR stuff.
Moveq #1,D0 ; Set for write.
Bsr MFMTrack ;
Cmp.b #0,D0 ; Check for error.
Bne @21 ; Error? Then go save error and retry.
Move.w D6,D2 ; Sectors to write. <SM24>
Ext.l D2 ; Force long. <SM24>
Asl.w #8,D2 ; Multiply by 512. <SM24>
Asl.w #1,D2 ; <SM24>
Bra @UpdateCnt ;
;;;;;;;;;;;;;;;; End of addittion <SM12>
@SendCommand Move.b #WriteData,D0 ; Setup write command.
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR?
Bgt.s @4 ; No? Then leave FM bit.
Bclr #fFM,D0 ; Clear FM bit.
@4 Bsr WriteToFDC ; Send command.
Move.b D7,D0 ; Head select.
Lsl.b #fHd,D0 ; Move into position.
Or.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Write head/drive.
Move.w D3,D0 ; Cylinder/Sector.
Bsr WriteToFDC ; Write cylinder number.
Move.b D7,D0 ; Head.
Bsr WriteToFDC ; Write head number.
Move.l D3,D0 ; Sector:Cyclinder.
Swap D0 ; Sector in low word.
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR format?
Ble.s @5 ; Yes? Then sectors are 0 based.
Addq.b #1,D0 ; Force sector number to be 1 based.
@5 Move.w D0,D2 ; Save starting sector.
Bsr WriteToFDC ; Write sector number.
Move.b fCode(A1),D0 ; Format byte (512 bytes/sector).
Bsr WriteToFDC ; Write format byte.
Move.b D6,D0 ; Sectors to write.
Add.b D2,D0 ; 0 or 1 based flag.
Subq.b #1,D0
Bsr WriteToFDC ; EOT (last sector to read).
Moveq #GSL,D0 ; Gap 3 length. <SM8>
Bsr WriteToFDC ; Write gap length.
Move.w D6,D2 ; Sectors to write.
Ext.l D2 ; Force long.
Asl.w #8,D2 ; Multiply by 512.
Asl.w #1,D2
Move.l #pscControl32,A3 ; PSC control register.
Move.w #(1 << pscPause) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause PSC.
@waitfrozen Move.w (A3), D0 ; <SM3>
Btst.l #pscFrozen, D0 ; <SM3>
Beq.s @waitfrozen ; check for pause <SM3>
Move.w (A3),D0 ; Control setting.
And.w #$1,D0 ; Get set.
Asl.w #4,D0 ; Calculate offset to correct set.
Movea.l #pscSet032,A5 ; DMA register set.
Move.l fBuffer(A1),pscAddress(A5,D0.w) ; Set address.
Move.l D2,pscCount(A5,D0.w) ; Set count. <SM21>
Move.w #(1 << pscDir) | \ ;
(0 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to write.
Move.w #(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Enable it.
Move.w #(1 << pscPause) | \ ;
(0 << pscSense), \ ;
(A3) ; Un-pause.
Move.w #1,fResult(A1) ; Set result to “in progress”.
Moveq #0,D0 ; DTL (no special sector size).
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Write DTL.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #2,D1 ; DBRA/4 Millisecond.
@Wait Bsr GetResult ; Check for interrupt. <SM23>
Cmp.w #0,fResult(A1) ; Result.
Ble.s @DoneDMA ; Done? Out of here.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
If Break Then
_debugger
EndIf
Bsr ResetFDC ; If timeout then something horrible happened. <SM20>
Bsr SetupFDC ; Everything needs to be reset. <SM20>
Move.w #noNybErr,fResult(A1); Report as timeout error. <SM20>
@DoneDMA Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w #(1 << pscSWReset) | \ ;
(1 << pscSense), \ ;
(A3) ; Reset channel.
Move.w fResult(A1),D0 ; Result.
Beq.s @UpdateCnt ; OK? Then update counter.
@21 Move.l fError2(A1),fError3(A1)
Move.l fError2+4(A1),fError3+4(A1)
Move.l fError1(A1),fError2(A1)
Move.l fError1+4(A1),fError2+4(A1)
Move.l fStatus0(A1),fError1(A1)
Move.l fStatus0+4(A1),fError1+4(A1)
Subq.b #1,fRetries(A1) ; Decrement retry counter.
Bgt @SendCommand ; More retries left? Then try again.
Bmi.s @Fail ; Did we recalibrate?
Bsr Track0 ; No? Then try recalibrating.
Tst.w fResult(A1) ; Error?
Bne.s @Fail ; Yes? then fail. <LW18>
Move.w D3,D2 ; Cylinder number.
Bsr SeekToTrack ; Seek to it.
Tst.w fResult(A1) ; Error?
Bne.s @Fail ; Yes? then fail. <LW18>
Bra @SendCommand ; And try one more time.
@Fail Addq.w #1,fHardErrors(A1) ; Bump hard error counter.
Clr.w fCount(A1) ; Void buffer.
Bra.s @ExitWrite ; And leave.
@UpdateCnt Add.l D2,ioActCount(A4) ; Update actual count.
Move.b fRetrySeed(A1),D0 ; Initial seed value.
Cmp.b fRetries(A1),D0 ; Did we have to perform a retry?
Beq @WriteLoop ; No? Then just continue.
Addq.w #1,fSoftErrors(A1) ; Yes? Then bump soft errors.
Move.b D0,fRetries(A1) ; Reset counter.
Bra @WriteLoop
@ExitWrite Move.l ioActCount(A4),D0 ; Bytes read.
Add.l D0,fPosition(A1) ; Update position.
Move.l fPosition(A1),ioPosOffset(A4) ; Update position offset.
Rts ; Return.
GCR1Side Dc.w 12,11,10,9,8 ; Sectors/cylinder.
Dc.w 192,176,160,144,128 ; Sectors/zone.
GCR2Side Dc.w 24,22,20,18,16 ; Sectors/cylinder.
Dc.w 384,352,320,288,256 ; Sectors/zone.
SectorsSide Dc.w 0,0,0,0,0,0,9,18,36 ; Sectors/side for all formats.
; Add ReadATrack Routine <SM12>
; Modified ReadATrack to MFMTrack <SM23>
;------------------------------------------------------------------------------
; Routine: MFMTrack
; Inputs: A0 -> Newage Address
; A1 -> Floppy info record.
; A4 -> Parameter block.
; D3.l -> Cylinder.
; D6.l -> # of sector/track.
; D7 -> Head(side).
; Outputs: D0 -> 0 = Pass.
; Function: Read a track.
; Called by: DoRead
;------------------------------------------------------------------------------
TrackRegs REG A3-A5/D2-D6 ; Save these registers.
MFMTrack Movem.l TrackRegs,-(Sp) ; Scratch registers.
Moveq #0,D2 ; Clear register.
Move.w D0,D2 ; Read/Write flag.
Swap D2 ; Save it.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #ReadMFMID,D0 ; Read ID Command.
Bsr WriteToFDC ; Write command.
Move.b D7,D0 ; Head select.
Lsl.b #fHd,D0 ; Move into position.
Or.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts.
Bsr WriteToFDC ; Write head/drive.
Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Waitx Bsr GetResult ; Go check for interrupt.
Cmp.b #-1,fStatus0(A1) ; Wait for status to change.
Bne.s @3 ; Change? Then check it.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Waitx ; Loop until it changes.
Move.b #EnableFDCInt,VIA2IER; Enable interrupts.
If Break Then
_debugger
EndIf
Bsr ResetFDC ; Time out. Reset FDC.
Bsr SetUpFDC ; And then restore the world.
Move.w #noAdrMkErr,fResult(A1) ; Assume blank disk.
Bra @ExitTrack ; Leave with error.
@3 Move.b fSector(A1),D2 ; Current sector number.
Swap D6 ;
Cmp.b D2,D6 ; Compare current sector with last sector.
Bne.s @4 ; Not equal?
Move.w #0,D2 ; Wrap it around.
@4 Moveq #0,D4 ; Clear address value.
Moveq #0,D5 ; Clear count value.
Swap D3 ; Get first sector requested.
; Assume current sector is before the first requested sector and set up accordingly.
Move.l fBuffer(A1),D4 ; Address for PSC active set.
Swap D2 ; Get read/write flag.
Cmp.b #0,D2 ; Is it read?
Beq.s @forread ; Yes? set up for read.
Swap D6 ; Get Number of sectors to write.
Move.w D6,D5 ; Get Number of sectors to write.
Move.b D6,D0 ; Get number of sectors to write.
Add.b D3,D0 ; Last sector to write.
Swap D6 ; In high word.
Swap D2 ; In high word.
Cmp.b D0,D2 ; Is current sector beyond last sector?
Blt.s @10 ; No? Just continue.
Move.w #0,D2 ; Reset currnet.
Bra.s @10 ;
@forread Swap D2 ; Get current sector.
Move.w D6,D5 ; Get Last.
Sub.w D3,D5 ; Subtract first from last.
@10 Asl.w #8,D5 ; Multiply by 512.
Asl.w #1,D5
Cmp.b D3,D2 ; Is current before or after first requested sector?
Ble.s @SetPsc ; Before? Every thing is all set.
Moveq #0,D1 ; Clear.
Move.b D2,D1 ; Get current.
Sub.b D3,D1 ; The difference between actual start
Asl.w #8,D1 ; and requested first start.
Asl.w #1,D1 ; Then multiply by 512 to the bytes.
Add.l D1,D4 ; Fix address of buffer.
Sub.l D1,D5 ; And the count.
@SetPsc Move.l #pscControl32,A3 ; PSC control register.
Move.w #(1 << pscPause) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause channel.
@waitfrozen Move.w (A3), D0 ;
Btst.l #pscFrozen, D0 ;
Beq.s @waitfrozen ; Check for pause.
Move.w (A3),D0 ; Control setting.
And.w #$1,D0 ; Get set.
Asl.w #4,D0 ; Calculate offset to correct set.
Move.l #pscSet032,A5 ; DMA register set.
Move.l D4,pscAddress(A5,D0.w) ; Set address.
Move.l D5,pscCount(A5,D0.w) ; Set count.
Swap D2 ; Get read/write flag.
Cmp.b #0,D2 ; Is it read?
Beq.s @SetRead1 ; Yes? set up for read.
Move.w #(1 << pscDir) | \ ;
(0 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to write.
Move.w #(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Enable it.
Bra.s @16 ;
@SetRead1 Move.w #(1 << pscDir) | \ ;
(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to read and enable.
@16 Swap D2
Cmp.b D3,D2 ; Is current before or after first requested sector?
Ble.s @UnpausePSC ; Before? Every thing is all set.
Bchg #4,D0 ; Switchset.
Move.l fBuffer(A1),pscAddress(A5,D0.w) ; Set address.
Move.l D1,pscCount(A5,D0.w) ; Set count.
Swap D2 ; Get read/write flag.
Cmp.b #0,D2 ; Is it read?
Bne.s @17 ; No? Out of here.
Move.w #(1 << pscDir) | \ ;
(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to read and enable.
@17 Swap D2 ;
@UnpausePSC Move.w #(1 << pscPause) | \ ;
(0 << pscSense), \ ;
(A3) ; Un-pause.
; Assume current sector is before the first requested sector and set up accordingly.
Move.b D3,D4 ; First sector to read.
Add.b #1,D4 ; Make it one base.
Swap D2 ; Get read/write flag.
Cmp.b #0,D2 ; Is it read?
Beq.s @lastread ; Yes? set up for read.
Move.l D6,D5 ;
Swap D5 ; Get number of sector to write.
Add.b D3,D5 ; Last sector to write.
Bra.s @11
@lastread Move.b D6,D5 ; Last sector to read.
@11 Swap D2 ; Get current sector.
Cmp.b D3,D2 ; Is current before or after first requested sector?
Ble.s @13 ; Before? Every thing is all set.
Move.b D2,D4 ; Current sector.
Add.b #1,D4 ; Start at next sector.
@13 Move.l D2,D0 ;
Swap D0 ; Get read/write flag.
Cmp.b #0,D0 ; Is it read
Beq.s @MFMRead ; Yes
@MFMWrite Move.b #WriteData,D0 ; Setup write command.
Bra.s @12 ;
@MFMRead Move.b #ReadData,D0 ; Setup read command.
@12 Bsr WriteToFDC ; Send command.
Move.b D7,D0 ; Head select.
Lsl.b #fHd,D0 ; Move into position.
Or.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Write head/drive.
Move.l D3,D0 ; Cylinder.
Swap D0 ;
Bsr WriteToFDC ; Write cylinder number.
Move.b D7,D0 ; Head.
Bsr WriteToFDC ; Write head number.
Move.b D4,D0 ; Starting sector.
Bsr WriteToFDC ; Write sector number.
Move.b fCode(A1),D0 ; Format byte (512 bytes/sector).
Bsr WriteToFDC ; Write format byte.
Move.b D5,D0 ; Last sector to read.
Bsr WriteToFDC ; EOT (last sector to read).
Moveq #GSL,D0 ; Gap 3 length.
Bsr WriteToFDC ; Write gap length.
Move.w #1,fResult(A1) ; Set result to “in progress”.
Moveq #0,D0 ; DTL (no special sector size).
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts.
Bsr WriteToFDC ; Write DTL.
Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #2,D1 ; DBRA/4 Millisecond.
@Wait Bsr GetResult ; Check for interrupt.
Cmp.w #0,fResult(A1) ; Result.
Ble.s @DoneDMA ; Done? Out of here.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts.
If Break Then
_debugger
EndIf
Bsr ResetFDC ; If timeout then something horrible happened.
Bsr SetupFDC ; Everything needs to be reset.
Move.w #noNybErr,fResult(A1); Report as timeout error.
@DoneDMA Move.b #EnableFDCInt,VIA2IER ; Enable interrupts.
Cmp.w #0,fResult(A1) ; Result.
Bne.s @ResetPSC ; Exit if error occurs.
Cmp.b D3,D2 ; Is current before or after first requested sector?
Ble.s @ResetPSC ; Before? Every is done. Out of here.
Move.b D3,D4 ;
Add.b #1,D4 ;
Move.b D2,D5 ;
Move.w #0,D2 ; The terminating condition.
Move.l D2,D0 ; Get read/write flag.
Swap D0 ; In high word.
Cmp.b #0,D0 ;
Beq.s @14 ; Read?
Move.w (A3),D0 ; Control setting.
And.w #$1,D0 ; Get set.
Asl.w #4,D0 ; Calculate offset to correct set.
Move.w #(1 << pscDir) | \ ;
(0 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to write.
Move.w #(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Enable it.
Bra @MFMWrite ;
@14 Bra @MFMRead ;
@ResetPSC Move.w #(1 << pscSWReset) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause channel.
@ExitTrack Move.w fResult(A1),D0 ; Result.
Movem.l (Sp)+,TrackRegs ; Restore registers.
Rts ; Done
;------------------------------------------------------------------------------
; Routine: ReadAGCRTrack
; Inputs: A0 -> Newage Address
; A1 -> Floppy info record.
; A4 -> Parameter block.
; D3.l -> Cylinder.
; D6.l -> # of sector/track.
; D7 -> Head(side).
; Outputs: D0 -> 0 = Pass.
; Function: Read a track.
; Called by: DoRead
;------------------------------------------------------------------------------
GCRTrackRegs REG A3-A5/D6 ; Save these registers.
ReadAGCRTrack Movem.l GCRTrackRegs,-(Sp) ; Scratch registers.
Move.l #pscControl32,A3 ; PSC control register.
Move.w #(1 << pscPause) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause channel.
@waitfrozen Move.w (A3), D0 ;
Btst.l #pscFrozen, D0 ;
Beq.s @waitfrozen ; Check for pause.
Move.w (A3),D0 ; Control setting.
And.w #$1,D0 ; Get set.
Asl.w #4,D0 ; Calculate offset to correct set.
Move.l #pscSet032,A5 ; DMA register set.
Move.l fBuffer(A1),pscAddress(A5,D0.w) ; Set address.
Swap D6 ;
Move.w D6,D1 ; Sectors per track.
Swap D3 ; Get starting sector.
Sub.w D3,D1 ; Number of sector from starting sector to end of track.
Swap D3 ;
Ext.l D1 ; Force long.
Asl.w #8,D1 ; Multiply by 512.
Asl.w #1,D1
Move.l D1,pscCount(A5,D0.w); Set count.
Move.w #(1 << pscDir) | \ ;
(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to read and enable.
Move.w #(1 << pscPause) | \ ;
(0 << pscSense), \ ;
(A3) ; Un-pause.
Move.b #ReadData,D0 ; Setup read command.
Bclr #fFM,D0 ; Clear FM bit.
Bsr WriteToFDC ; Send command.
Move.b D7,D0 ; Head select.
Lsl.b #fHd,D0 ; Move into position.
Or.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Write head/drive.
Move.b D3,D0 ; Cylinder.
Bsr WriteToFDC ; Write cylinder number.
Move.b D7,D0 ; Head.
Bsr WriteToFDC ; Write head number.
Move.l D3,D0 ; Sector:Cyclinder.
Swap D0 ; Sector in low word.
Bsr WriteToFDC ; Write sector number.
Move.b fCode(A1),D0 ; Format byte (512 bytes/sector).
Bsr WriteToFDC ; Write format byte.
Move.b D6,D0 ; EOT.
Sub.b #1,D0 ; Make it zero base.
Bsr WriteToFDC ; EOT (last sector to read).
Moveq #GSL,D0 ; Gap 3 length.
Bsr WriteToFDC ; Write gap length.
Move.w #1,fResult(A1) ; Set result to “in progress”.
Moveq #0,D0 ; DTL (no special sector size).
Move.b #DisableFDCInt,VIA2IER; Disable interrupts.
Bsr WriteToFDC ; Write DTL.
Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #2,D1 ; DBRA/4 Millisecond.
@Wait Bsr GetResult ; Check for interrupt.
Cmp.w #0,fResult(A1) ; Result.
Ble.s @DoneDMA ; Done? Out of here.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts.
If Break Then
_debugger
EndIf
Bsr ResetFDC ; If timeout then something horrible happened.
Bsr SetupFDC ; Everything needs to be reset.
Move.w #noNybErr,fResult(A1); Report as timeout error.
@DoneDMA Move.b #EnableFDCInt,VIA2IER ; Enable interrupts.
Move.w #(1 << pscSWReset) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause channel.
@ExitTrack Move.w fResult(A1),D0 ; Result.
Movem.l (Sp)+,GCRTrackRegs ; Restore registers.
Rts ; Done
;------------------------------------------------------------------------------
; Routine: Control
; Inputs: A0 -> Parameter block.
; A1 -> DCE.
; Outputs: D0 -> 0 - OK, ~0 - Error.
; Function: Handle control requests.
;------------------------------------------------------------------------------
ControlRegs REG A0-A5/D3-D7 ; Registers abused.
Control
Movem.l ControlRegs,-(Sp) ; Scratch registers.
Movea.l A0,A4 ; Save parameter block.
Movea.l NewAgeVars,A3 ; DCE pointer.
Moveq #controlErr,D6 ; Assume failure.
Move.w csCode(A4),D0 ; CSCode.
Lea ControlVectors,A0 ; Vector table.
@Loop Cmp.w (A0),D0 ; Match?
Beq.s @CallIt ; Yes? Then call it.
Tst.l (A0)+ ; Next vector.
Bne.s @Loop ; Does it exist? Then check it.
Bra.s @ExitControl ; No? Then leave with error.
@CallIt Move.w 2(A0),D0 ; Offset.
Beq.s @ExitControl ; Leave if no routine.
Jsr ControlVectors(D0) ; Call it.
@ExitControl
Move.w D6,D0 ; Call result.
Movem.l (Sp)+,ControlRegs ; Restore registers.
Move.w D0,ioResult(A0) ; Set result value.
Move.w ioTrap(A0),D1 ; Trap called.
Btst #noQueueBit,D1 ; Called immediately?
Bne.s @2 ; Yes? Then leave via an RTS.
Tst.w D0 ; Completed?
Ble.s @1 ; Yes? Then go through IODone.
Btst #asyncTrpBit,D1 ; Called asynchronously?
Bne.s @2 ; Yes? Then leave via an RTS.
@1 Move.l JIODone,-(Sp) ; Vector to IODone.
@2 Rts ; Return.
ControlVectors Dc.w 01,KillIO - ControlVectors
Dc.w 05,VerifyDisk - ControlVectors
Dc.w 06,FormatDisk - ControlVectors
Dc.w 07,EjectDisk - ControlVectors
Dc.w 08,TagBuffer - ControlVectors
Dc.w 09,TrackCache - ControlVectors
Dc.w 21,GetDriveIcon - ControlVectors
Dc.w 22,GetMediaIcon - ControlVectors
Dc.w 23,DriveInfo - ControlVectors
Dc.w 65,CheckMotor - ControlVectors
; Apple use only routines…
Dc.w 18244,TrackDump - ControlVectors
Dc.w 21315,DiskCopy - ControlVectors
Dc.w 0, 0
;******************************************************************************
; KillIO (not supported).
;******************************************************************************
KillIO Moveq #-1,D6 ; Result.
Rts ; And return.
;******************************************************************************
; Verify disk in drive.
;******************************************************************************
VerifyDisk Link A6,#-ioQElSize ; Stack frame for PB.
Move.l A4,-(Sp) ; Save PB.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Move.w ioDrvNum(A4),D0 ; Drive number.
Cmp.w fDriveNum(A1),D0 ; Correct record?
Beq.s @Prepare ; Yes? Then use it.
Move.l fNextRecord(A1),A1 ; Next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Correct record? <SM16>
Beq.s @Prepare ; Yes? Then use it. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume no such drive. <SM16>
Bra.w @Exit ; Out of here. <SM16>
@Prepare Move.w #offLinErr,fResult(A1); Assume no disk.
Move.w fFormat(A1),D0 ; Format code.
Beq @Exitverify ; No disk? Leave.
Move.w #verErr,fResult(A1) ; Assume unformatted disk.
Cmp.w #fBlank,D0 ; Unknown format?
Beq.s @ExitVerify ; Yes? Then leave.
Lea FormatTable,A2 ; Pointer to format table.
@FindTable Cmp.w ftFormatCode(A2),D0 ; Correct format table?
Beq.s @InitRegisters ; Yes? Then prepare for verify.
Lea ftNextTable(A2),A2 ; Next table.
Bra.s @FindTable ; Check it.
@InitRegisters Moveq #1,D3 ; Head.
Moveq #0,D2 ; Starting cylinder.
Moveq #0,D5 ; Starting sector number.
Moveq #0,D6 ; Init register.
Move.b ftSectors(A2),D6 ; Number of sectors/track.
Moveq #(MFMCylndrs -1),D7 ; Tracks/zone for MFM (1 zone).
Move.l fBuffer(A1),A2 ; Buffer.
Clr.l fCount(A1) ; Invalidate cache <SM20>
Lea -ioQElSize(A6),A4 ; Parameter block.
Move.w fDriveNum(A1),ioDrvNum(A4)
Cmp.b #10,D6 ; Sector count equal 10?
Bne.s @DoCylinder ; No? Then MFM.
Moveq #12,D6 ; Starting sectors/track for GCR.
Moveq #(GCRCylndrs -1),D7 ; Tracks/zone for GCR (5 zones).
@DoCylinder Move.b #VerifyRetry,fRetrySeed(A1) ; Change the retry Count <SM30>
Move.b #VerifyRetry,fRetries(A1) ; Reset counter. <SM30>
@CylinderLoop Clr.l ioActCount(A4) ; Init count.
Move.w D6,D4 ; Sectors/track.
IF MTMode THEN
Cmp.w #f400K,fFormat(A1) ; Single sided?
Beq.s @0
Asl.w #1,D4 ; Do both sides if multi-track.
@0
ENDIF
Movem.l A2-A5/D2-D7,-(Sp) ; Save registers.
Bsr DoRead ; Read track (or cylinder).
Movem.l (Sp)+,A2-A5/D2-D7 ; Restore registers.
Tst.w fResult(A1) ; Any errors?
Bne.s @ExitVerify ; Yes? Then leave.
Add.w D4,D5 ; Next starting sector.
IF NOT MTMode THEN
Cmp.w #f400K,fFormat(A1) ; Single sided?
Beq.s @NextCylinder ; Yes? Then do next cylinder.
Subq.w #1,D3 ; Next side.
Neg.w D3 ; Still positive?
Beq.s @CylinderLoop ; Yes? Then do it.
ENDIF
@NextCylinder Addq.w #1,D2 ; Next cylinder.
Dbra D7,@CylinderLoop ; Cylinders left in this zone? Do it.
Subq.w #1,D6 ; Decrement sectors/cylinder.
Moveq #(GCRCylndrs -1),D7 ; Reset cylinders/zone.
Cmp.w #DiskCylndrs,D2 ; Done?
Blt.s @CylinderLoop ; No? Then do it.
@ExitVerify Move.l Ticks,fLastAccess(A1)
Move.b #RetryCount,fRetrySeed(A1) ; Reset the retry Count <SM30>
Move.b #RetryCount,fRetries(A1) ; Reset counter. <SM30>
Move.w fResult(A1),D6 ; Result.
Move.l #NewAge32,A0 ; Base address of NewAge.
Bsr Track0 ; Recalibrate.
@Exit Move.l (Sp)+,A4
Unlk A6
Rts ; And leave.
;******************************************************************************
; Format disk in drive.
;******************************************************************************
FormatDisk Move.l #NewAge32,A0 ; Base address of NewAge.
Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Correct record?
Beq.s @SetUp ; Yes? Then use it.
Move.l fNextRecord(A1),A1 ; Next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Correct record? <SM16>
Beq.s @SetUp ; Yes? Then use it. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume no such drive. <SM16>
Bra.w @Exit ; Out of here. <SM16>
@SetUp Lea FormatTable,A2 ; Start of format table.
Move.w #paramErr,D6 ; Assume parameter error.
Move.w csParam(A4),D0 ; Format index.
Blt @ExitFormat ; Offset better be greater than 0. <SM16>
Bgt.s @5 ; Check for zero. <SM20>
Cmp.w #fBlank,fFormat(A1) ; Is it a blank disk, format it. <LW5>
Beq.s @ValidFormat ; Yes? Then format. <LW5>
Move.w fFormat(A1),D0 ; Get current format. <LW5>
Cmp.w #fUnknownGCR,D0 ; Is it a GCR disk? <LW5>
Blt.s @IsGCR ; Yes? Then reformat as same type. <LW5>
Cmp.w #f720K,D0 ; Is it a MFM LD disk? <LW5>
Beq.s @IsLDMFM ; Yes? Then reformat as same type. <LW5>
Bra.s @ValidFormat ; All other format as 1 <LW5>
@IsGCR Sub.w #1,D0 ; GCR format. <LW5>
bra.s @5 ; Done. <LW5>
@IsLDMFM Move.w #4,D0 ; Low density MFM disk. <LW5>
bra.s @5 ; Done. <LW5>
@ValidFormat Move.w #1,D0 ; Give it a valid format number. <LW5>
@5 Cmp.w #4,D0 ; Check that param. is within limit. <SM16>
Bgt.w @ExitFormat ; Offset better be less than 4. <SM16>
Lea AppleDrv,A3 ; Assume 800K drive installed.
Cmp.w #fddMac800,fDriveType(A1) ; 800K drive?
Beq.s @GetTable ; Yes? Then only GCR.
Lea LowDensity,A3 ; Assume low density media inserted.
Cmp.w #mLD,fMediaType(A1) ; Low denisty disk?
Beq.s @GetTable ; Yes? Then find table.
Lea HighDensity,A3 ; Assume high density media inserted.
Cmp.w #mHD,fMediaType(A1) ; High denisty disk?
Beq.s @GetTable ; Yes? Then find table.
Lea ExtendedDensity,A3 ; Must be extended density media.
@GetTable Subq.w #1,D0 ; Make zero based.
Asl.w #1,D0 ; Make word index.
Move.w (A3,D0.w),D0 ; Get offset <SM16>
Cmp.w #-1,D0 ; Check to see if offset is okay. <SM16>
Beq.w @ExitFormat ; <SM16>
Adda.w D0,A2 ; Add offset to table. <SM16>
Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #$0,D0 ; Standard.
Cmp.w #f2880K,ftFormatCode(A2) ; Extended density?
Bne.s @0 ; No? Then horizontal mode.
Moveq #vertical,D0 ; Yes? Set vertical mode.
@0 Bsr WriteToFDC ; Send it.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetDriveGCR,D0 ; Set drive mode to GCR.
Moveq #(dr500 << DataRateOffset),D1 ; Data rate.
Cmp.w #fUnknownGCR,ftFormatCode(A2) ; GCR format?
Ble.s @1 ; Yes? Then set it.
Move.b #SetDriveMFM,D0 ; Set drive to MFM.
Moveq #(dr500 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Date rate/pre-comp for HD.
Cmp.w #f1440K,ftFormatCode(A2) ; Double density?
Ble.s @1 ; Yes? Then set it.
Moveq #(dr1000 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Must be extended density.
@1 Move.b D1,fdcDRR(A0) ; Set data rate/pre-comp.
Bsr WriteToFDC ; Send mode byte.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send it.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Waitx Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Done?
Bne.s @Donex ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Waitx ; Loop
Move.w #noNybErr,fResult(A1) ; Error?
If Break Then
_debugger
EndIf
@Donex Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w fResult(A1),D6 ; Error?
Bne @ExitFormat ; Yes? Out of here.
Bsr Track0 ; Recalibrate drive.
Move.w fResult(A1),D6 ; Get error code.
Bne @ExitFormat ; Error? then fail. <LW18>
Moveq #0,D2 ; Starting cylinder number.
Moveq #0,D7 ; Init sync group flag.
Moveq #0,D4 ; Init register.
Move.b ftSectors(A2),D4 ; Number of sectors/track.
Move.b ftGap3Length(A2),D7 ; Gap3 length or number of sync groups.
Moveq #(MFMCylndrs -1),D5 ; Tracks/zone for MFM (1 zone).
Move.b #Format,D6 ; Format command.
Lea MFMInterleave,A4 ; Interleave table.
Cmp.b #10,D4 ; Sector count equal 10?
Bne.s @CylinderLoop ; No? Then MFM.
Moveq #12,D4 ; Starting sectors/track for GCR.
Moveq #(GCRCylndrs -1),D5 ; Tracks/zone for GCR (5 zones).
Bclr #fFM,D6 ; Clear MFM flag.
Lea Zone1_2,A4 ; 2:1 interleave table.
Cmp.b #formatGCR4_1,ftFormatByte(A2) ; 4:1 interleave?
Bne.s @CylinderLoop ; No? Then we have the right table.
Lea Zone1_4,A4 ; Yes? 4:1 interleave table.
@CylinderLoop Moveq #0,D3 ; Starting head.
Bsr SeekToTrack ; Seek to cylinder.
Tst.w fResult(A1) ; Error?
Bne @FormatError ; If so report it. <LW18>
@SideLoop Move.b D6,D0 ; Format command.
Bsr WriteToFDC ; Write command.
Move.b D3,D0 ; Head select.
Lsl.b #fHd,D0 ; Move into position.
Or.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Write head/drive.
Move.b ftFormatByte(A2),D0 ; 512 bytes/sector (format code).
Bsr WriteToFDC ; Write bytes/sector.
Move.b D4,D0 ; Sectors/track.
Bsr WriteToFDC ; Write sectors/track.
Move.b D7,D0 ; GCR sync groups or MFM Gap3 length.
Btst #fFM,D6 ; Is this a MFM format? <LW7>
Bne.s @WriteSync ; Yes? The just write GAP3 length. <LW7>
Btst #15,D7 ; Is this the real format? <LW7>
Bne.s @WriteSync ; Yes? Then write the correct number of Sync Group. <LW7>
Move.b #$3f,D0 ; Give it a large number of Sync Group for Bogus format. <LW7>
@WriteSync Bsr WriteToFDC ; Write Gap3 length (or sync groups).
Move.l fBuffer(A1),A3 ; Pointer to buffer.
Move.w D4,D0 ; Sectors/track.
Subq.w #1,D0 ; For looping.
Move.l A4,A5 ; Interleave table.
@BufferLoop Move.b D2,(A3)+ ; Track.
Move.b D3,(A3)+ ; Side.
Btst #fFM,D6 ; Is this a MFM format? <LW7>
Bne.s @Sector ; Yes? The give the correct Sector number. <LW7>
Btst #15,D7 ; Is this the real format? <LW7>
Bne.s @Sector ; Yes? Then give the correct Sector number. <LW7>
Move.b #$3f,(A3)+ ; Give it a bogus Sector number <LW7>
Bra.s @FormatByte ; And Continue... <LW7>
@Sector Move.b (A5)+,(A3)+ ; Sector.
@FormatByte Move.b ftFormatByte(A2),(A3)+ ; Format byte.
Dbra D0,@BufferLoop ; Loop till done.
Swap D5 ; Scratch in low word.
Move.w D4,D5 ; Sectors/track.
Asl.w #2,D5 ; Bytes to transfer.
Move.l #pscControl32,A3 ; PSC control register.
Move.w #(1 << pscPause) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause channel.
@waitfrozen Move.w (A3), D0 ; <SM3>
Btst.l #pscFrozen, D0 ; <SM3>
Beq.s @waitfrozen ; Check that pause bit is frozen. <SM3>
Move.w (A3),D0 ; Control setting.
And.w #$1,D0 ; Get set.
Asl.w #4,D0 ; Calculate offset to correct set.
Move.l #pscSet032,A5 ; DMA register set.
Move.l fBuffer(A1),pscAddress(A5,D0.w) ; Set address.
Moveq #0,D1 ; Init register.
Move.w D5,D1 ; Bytes to transfer.
Move.l D1,pscCount(A5,D0.w); Set count.
Move.w #(1 << pscDir) | \ ;
(0 << pscSense), \ ;
pscStatus(A5,D0.w) ; Set direction to write.
Move.w #(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A5,D0.w) ; Enable it.
Move.w #(1 << pscPause) | \ ;
(0 << pscSense), \ ;
(A3) ; Un-pause.
Move.w #1,fResult(A1) ; Set result to “in progress”.
Move.b #$F6,D0 ; Filler byte.
Btst #fFM,D6 ; MFM format?
Bne.s @3 ; Yes? Then fill with $F6.
Moveq #0,D0 ; GCR? Fill with 0.
@3 Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Write filler byte.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #2,D1 ; DBRA/4 Millisecond.
@Wait Bsr GetResult ; Check for interrupt. <SM23>
Cmp.w #0,fResult(A1) ; Result.
Ble.s @DoneDMA ; Done? Out of here.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
If Break Then
_debugger
EndIf
Bsr ResetFDC ; If timeout then something horrible happened. <SM20>
Move.w #noNybErr,fResult(A1) ; Report as timeout error. <SM20>
@DoneDMA Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w #(1 << pscSWReset) | \ ;
(1 << pscSense), \ ;
(A3) ; Reset channel.
Move.w fResult(A1),D0 ; Check error. <LW4>
Bne @FormatError ; <LW4>
Swap D5 ; Tracks/zone in low word.
Btst #fFM,D6 ; Formatting MFM?
Bne.s @NextSide ; Yes? Then do next side.
Move.w TimeDBRA,D1 ; DBRA/Millisecond. <LW7>
@StupidWait Dbra D1,@StupidWait ; <LW7>
Btst #15,D7 ; Was this pass real or just erasing the disk? <LW7>
Bne.s @ClearFlag ; Valid Format? Then clear flag and continue. <LW7>
Bset #15,D7 ; Set flag. <LW7>
Beq @SideLoop ; And Do the valid format. <LW7>
@ClearFlag Bclr #15,D7 ;
@NextSide Move.b ftSides(A2),D0 ; Flags/Sides.
And.b #$F,D0 ; Sides.
Cmp.b #1,D0 ; Single sided?
Beq.s @NextCylinder ; Yes? Then do next cylinder.
Addq.w #1,D3 ; Next side.
Cmp.w #1,D3 ; Side 1?
Beq @SideLoop ; Yes? Then do it.
@NextCylinder Addq.w #1,D2 ; Next cylinder.
Dbra D5,@CylinderLoop ; Cylinders left in this zone? Do it.
Adda.w #itNextZone,A4 ; Next interleave zone.
Subq.w #1,D4 ; Decrement sectors/cylinder.
Moveq #(GCRCylndrs -1),D5 ; Reset cylinders/zone.
Cmp.w #DiskCylndrs,D2 ; Done?
Blt @CylinderLoop ; No? Then do it.
Bsr Track0 ; Recalibrate.
Clr.b fCylinder(A1) ; Set track to 0.
Moveq #noErr,D6 ; Indicate no error.
Move.l fDriveQueue(A1),A3 ; Pointer to drive queue.
Move.w ftFormatCode(A2),fFormat(A1) ; Set media format.
Move.w ftBlocks(A2),dQDrvSz(A3) ; Number of blocks.
Move.b #$FF,-1(A3) ; Non single-sided. <LW14>
Move.b #1,-3(A3) ; Set “Disk in place” flag.
Cmp.w #f400K,fFormat(A1) ; 400K GCR?
Bne.s @ExitFormat ; No? Then double-sided.
Clr.b -1(A3) ; Single-sided.
@ExitFormat Move.l Ticks,fLastAccess(A1)
Clr.w fCount(A1) ; Void buffer.
@Exit Rts ; And leave.
@FormatError Move.w fResult(A1),D6 ; <LW4>
Bra.s @ExitFormat ; <LW4>
Zone1_2 Dc.b $0,$6,$1,$7,$2,$8,$3,$9,$4,$A,$5,$B
Zone2_2 Dc.b $0,$6,$1,$7,$2,$8,$3,$9,$4,$A,$5,$F
Zone3_2 Dc.b $0,$5,$1,$6,$2,$7,$3,$8,$4,$9,$F,$F
Zone4_2 Dc.b $0,$5,$1,$6,$2,$7,$3,$8,$4,$F,$F,$F
Zone5_2 Dc.b $0,$4,$1,$5,$2,$6,$3,$7,$F,$F,$F,$F
Zone1_4 Dc.b $0,$3,$6,$9,$1,$4,$7,$A,$2,$5,$8,$B
Zone2_4 Dc.b $0,$3,$6,$9,$1,$4,$7,$A,$2,$5,$8,$F
Zone3_4 Dc.b $0,$5,$3,$8,$1,$6,$4,$9,$2,$7,$F,$F
Zone4_4 Dc.b $0,$7,$5,$3,$1,$8,$6,$4,$2,$F,$F,$F
Zone5_4 Dc.b $0,$2,$4,$6,$1,$3,$5,$7,$F,$F,$F,$F
MFMInterleave Dc.b $01,$02,$03,$04,$05,$06,$07,$08,$09
Dc.b $0A,$0B,$0C,$0D,$0E,$0F,$10,$11,$12
Dc.b $13,$14,$15,$16,$17,$18,$19,$1A,$1B
Dc.b $1C,$1D,$1E,$1F,$20,$21,$22,$23,$24
;******************************************************************************
; Eject disk in drive.
;******************************************************************************
EjectDisk Move.l #NewAge32,A0 ; Base address of NewAge.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Move.w ioDrvNum(A4),D0 ; Drive number.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @CheckDrive ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Correct record? <SM16>
Beq.s @CheckDrive ; Yes? Then use it. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume no such drive. <SM16>
Bra @ExitEject ; Out of here.
@CheckDrive Move.l A3,fDCE(A1) ; Save DCE.
Move.l fDriveQueue(A1),A3 ; Pointer to drive queue.
; Add command to enable FDD <SM12>
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetEnableOn,D0 ; Set enable command.
Bsr WriteToFDC ; Send it.
Move.w fDriveSelect(A1),D0 ; Drive number.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Enable the drive.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Waitx Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Done?
Bne.s @changed ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Waitx ; Loop
Move.w #noNybErr,fResult(A1) ; Error?
If Break Then
_debugger
EndIf
; End of addtions <SM12>
@changed Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w fResult(A1),D6 ; Error?
Bne.s @ExitEject ; Yes? Out of here.
Cmp.b #1,-3(A3) ; First access?
Bne.s @Seek ; No? Then don't recalibrate.
Bsr Track0 ; Recalibrate.
@Seek Moveq #40,D2 ; Track 40.
Bsr SeekToTrack ; Park head.
Moveq #1,D6 ; Set busy.
Lea MotorOff,A2 ; Motor off routine.
Move.l A2,fCompletion(A1) ; Stuff routine pointer.
Move.b #EjectFloppy,D0 ; Eject command.
Bsr WriteToFDC ; Send command.
Move.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Eject it.
Clr.l -4(A3) ; Clear all flags.
Clr.w dQDrvSz(A3) ; Clear size.
Clr.w fFormat(A1) ; Clear format.
Clr.w fMediaType(A1) ; Clear media type.
Move.b #-1,fCylinder(A1) ; Flag unknown track.
Clr.w fStart(A1) ; Set starting sector in buffer to 0.
Clr.w fCount(A1) ; Set number of sectors in buffer to 0.
@ExitEject Rts ; And leave.
MotorOff Tst.b fMotor(A1) ; Motor on?
Beq.s @Exit ; No? Then leave.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetMotorOff,D0 ; Motor off command.
Bsr WriteToFDC ; Send command.
Move.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Send drive ID.
Clr.b fMotor(A1) ; Clear flag.
@Exit Move.b #SetEnableOff,D0 ; Disable drive.
Bsr WriteToFDC ; Send it.
Move.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Disable drive.
Moveq #noErr,D0 ; Set done.
Move.l fDCE(A1),A1 ; Pointer to DCE.
Move.l dCtlQHead(A1),A0 ; IO queue.
Move.w ioTrap(A0),D1 ; Trap called.
Btst #asyncTrpBit,D1 ; Called asynchronously?
Beq.s @0 ; No? Then return through RTS.
Move.l JIODone,-(Sp) ; Yes? Return through IODone.
@0 Rts
;******************************************************************************
; Set tag buffer (not supported).
;******************************************************************************
TagBuffer Rts ; Just return.
;******************************************************************************
; Set track cache (not supported).
;******************************************************************************
TrackCache Rts ; Just return.
;******************************************************************************
; Return drive icon and “where” info.
;******************************************************************************
; locate equates for offset in icon table…
itDrive EQU 1
itIcon EQU 2
itNextIcon EQU 6
GetDriveIcon Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @GetIcon ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Correct record? <SM16>
Beq.s @GetIcon ; Yes? Then use it. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Bra.s @ExitGetIcon ; No record? Then leave.
@GetIcon Lea IconTable,A2 ; Start of icon table.
Move.l A2,A0 ; Save pointer.
Move.b fDriveSelect(A1),D0 ; Drive select (0 or 1).
Move.b $CB3,D1 ; (BoxFlag) Box we're running on.
Move.w #controlErr,D6 ; Assume we can't find icon.
@IconLoop Tst.b (A2) ; End of table?
Beq.s @ExitGetIcon ; Yes? Then leave.
Cmp.b (A2),D1 ; Boxflag match?
Bne.s @Next ; No? Then check next entry.
Cmp.b itDrive(A2),D0 ; Right drive?
Bne.s @Next ; No? Then check next entry.
Adda.l itIcon(A2),A0 ; Pointer to icon.
Move.l A0,csParam(A4) ; Return pointer.
Moveq #noErr,D6 ; Indicate “no error”.
Bra.s @ExitGetIcon ; And leave.
@Next Adda.w #itNextIcon,A2 ; Next table.
Bra.s @IconLoop ; And check it.
@ExitGetIcon Rts ; Leave.
IconTable Dc.b 37,0 ; Cyclone33
Dc.l FrigidaireInternal - IconTable
Dc.b 72,0 ; Cyclone40 <LW9>
Dc.l FrigidaireInternal - IconTable
Dc.b 54,0 ; Tempest25 <LW9>
Dc.l QFCInternal - IconTable
Dc.b 73,0 ; Tempest33 <LW9>
Dc.l QFCInternal - IconTable
Dc.b 37,1 ; Non existing cyclone33 external
Dc.l FrigidaireExternal - IconTable
Dc.b 72,1 ; Non existing cyclone40 external <LW9>
Dc.l FrigidaireExternal - IconTable
Dc.b 54,1 ; Non existing Tempest25 external <LW9>
Dc.l QFCExternal - IconTable
Dc.b 73,1 ; Non existing Tempest33 external <LW9>
Dc.l QFCExternal - IconTable
Dc.b 0,0 ; End of table
;******************************************************************************
; Return media icon and “where” info.
;******************************************************************************
GetMediaIcon Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @GetIcon ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Match? <SM16>
Beq.s @GetIcon ; Yes? Then check for drive. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Bra.s @Exit ; No record? Then leave.
@GetIcon Pea MediaIcon ; Pointer to icon data.
Move.l (Sp)+,csParam(A4)
Moveq #noErr,D6 ; Indicate no error.
@Exit Rts ; And leave.
;******************************************************************************
; Return drive info.
;******************************************************************************
DriveInfo Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @BuildRecord ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Match? <SM16>
Beq.s @BuildRecord ; Yes? Then check for drive. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Bra.s @ExitDriveInfo ; No record? Then leave.
@BuildRecord Moveq #noErr,D6 ; No error.
Moveq #0,D2 ; Init record.
Move.w fDriveType(A1),D2 ; Drive type.
Tst.b fDriveSelect(A1) ; First drive found?
Beq.s @ExitDriveInfo ; Yes? Then “primary” drive.
Bset #11,D2 ; “Secondary” drive.
Bset #8,D2 ; External drive.
@ExitDriveInfo Move.l D2,csParam(A4) ; Put it in the right place
Rts ; And leave.
;******************************************************************************
; Check idle motor.
;******************************************************************************
CheckMotor Move.l #NewAge32,A0 ; Base address of NewAge.
Move.l dCtlStorage(A3),D0 ; Pointer to floppy info.
@Loop Beq.s @ExitMotor ; No record? Then leave.
Move.l D0,A1 ; Pointer to record.
Tst.b fMotor(A1) ; Motor on?
Beq.s @Next ; No? Then check next drive.
Move.l fLastAccess(A1),D0 ; Last time accessed.
Add.l #WaitTime,D0 ; Add timeout.
Cmp.l Ticks,D0 ; Time up?
Bgt.s @Next ; No? Then let drive spin.
Move.b #SetMotorOff,D0 ; Motor off command.
Bsr WriteToFDC ; Send command.
Move.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Send drive ID.
Clr.b fMotor(A1) ; Clear flag.
@Next Move.l fNextRecord(A1),D0 ; Next record.
Bra.s @Loop ; Loop till we're done.
@ExitMotor Moveq #noErr,D6 ; Indicate no error.
Rts ; And leave.
;******************************************************************************
; Diagnostic raw track dump.
; For technical reasons (since clock and data streams have to be
; seperated in real time) RawDump is performed only in non-DMA mode.
;******************************************************************************
TrackDump Move.l #NewAge32,A0 ; Base address of NewAge.
Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Correct record?
Beq.s @SetUp ; Yes? Then use it.
Move.l fNextRecord(A1),A1 ; Next record.
Beq.s @99 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Drive numbers match? <SM16>
Beq.s @SetUp ; Yes? Then use it. <SM16>
@99 Move.w #nsDrvErr,D6 ; Let's make sure drive exists. <SM16>
Bra @ExitTrackDump ; No? Then let's bail. <SM16>
@SetUp Move.w #offLinErr,D6 ; Check to see if we have a media.
Tst.w fMediaType(A1) ; Disk in place?
Beq @ExitTrackDump ; No? What do they expect us to do?
Move.w #noErr,D6 ; Assume no error.
Clr.l csParam+12(A4) ; Assume we can't read anything.
Move.l csParam+8(A4),D7 ; Count 0?
Beq @ExitTrackDump ; Yes? Then leave without doing it.
Tst.l csParam+0(A4) ; Clock buffer nil?
Sne D5 ; Set flag.
Lsl.w #1,D5 ; Move flag to second byte.
Tst.l csParam+4(A4) ; Data buffer nil?
Sne D5 ; Set flag.
Lsr.w #7,D5 ; Bit 0 - data flag; bit 1 - clock flag.
Tst.b D5 ; Any buffers?
Beq @ExitTrackDump ; No? Then can't do anything.
@RangeCheck Move.w #paramErr,D6 ; Assume parameter error.
Move.w csParam+18(A4),D2 ; Track number.
Bmi @ExitTrackDump ; Less than 0? NOT!
Cmp.w #(DiskCylndrs -1),D2 ; Greater than 79?
Bgt @ExitTrackDump ; NOT!
Move.b csParam+20(A4),D3 ; Head.
Bmi @ExitTrackDump ; Less than 0? NOT!
Cmp.b #1,D3 ; Greater than 1?
Bgt @ExitTrackDump ; NOT!
Move.w csParam+16(A4),D4 ; Search mode.
Bmi @ExitTrackDump ; Less than 0? (This is getting boring!)
Cmp.w #3,D4 ; Greater …
Bgt @ExitTrackDump ; Yea, yea.
Blt.s @CheckMedia ; Type 3 only works for MFM.
Cmp.w #fUnknownGCR,fFormat(A1) ; So let's make sure media is MFM.
Ble @ExitTrackDump ; GCR? No way man.
@CheckMedia Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #$0,D0 ; Standard.
Cmp.w #f2880K,fFormat(A1) ; Extended density?
Bne.s @0 ; No? Then horizontal mode.
Moveq #vertical,D0 ; Yes? Set vertical mode.
@0 Bsr WriteToFDC ; Send it.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetDriveGCR,D0 ; Set drive mode to GCR.
Moveq #(dr500 << DataRateOffset),D1 ; Data rate.
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR format?
Ble.s @1 ; Yes? Then set it.
Move.b #SetDriveMFM,D0 ; Set drive to MFM.
Moveq #(dr500 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Date rate/pre-comp for HD.
Cmp.w #f1440K,fFormat(A1) ; Double density?
Ble.s @1 ; Yes? Then set it.
Moveq #(dr1000 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Must be extended density.
@1 Move.b D1,fdcDRR(A0) ; Set data rate/pre-comp.
Bsr WriteToFDC ; Send mode byte.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send it.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Waitx Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Done?
Bne.s @Donex ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Waitx ; Loop
Move.w #noNybErr,fResult(A1) ; Error?
If Break Then
_debugger
EndIf
@Donex Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w fResult(A1),D6 ; Error?
Bne @ExitTrackDump ; Yes? Out of here.
Move.b #Specify,D0 ; Specify command.
Bsr WriteToFDC ; Send byte to FDC.
Moveq #0,D0 ; Step rate/head unload.
Bsr WriteToFDC ; Send byte to FDC.
Moveq #1,D0 ; Head load/Non-DMA.
Bsr WriteToFDC ; Send byte to FDC.
Bsr SeekToTrack ; Seek to track.
Move.l csParam(A4),A2 ; Clock buffer.
Move.l csParam+4(A4),A3 ; Data buffer.
Move.w #RawDump,D0 ; Command.
Cmp.w #fUnknownGCR,fFormat(A1) ; MFM?
Bgt.s @SendCommand ; Yes? Then send command.
Bclr #fFM,D0 ; Set it to GCR.
Bclr #1,D5 ; Don't save clocks.
@SendCommand Bsr WriteToFDC ; Send it.
Move.b csParam+21(A4),D2 ; Starting sector.
Moveq #0,D0 ; Assume dump from index.
Cmp.w #3,D4 ; Search from index?
Beq.s @SetHead ; Yes? Then set head bit.
Moveq #$10,D0 ; Assume dump from data mark.
Cmp.w #2,D4 ; Dump from data mark?
Beq.s @SetHead ; Yes? Then set head bit.
Moveq #$8,D0 ; Assume dump from address mark.
Cmp.w #1,D4 ; Dump from address?
Beq.s @SetHead ; Yes? Then set head bit.
Moveq #1,D2 ; Must be dump immediate. Since
; NewAge doesn't support this, we'll
; dump from Address 1. Hope this is OK.
Cmp.w #fUnknownGCR,fFormat(A1) ; MFM? <LW26>
Bgt.s @SetHead ; Yes? Then send command. <LW26>
Moveq #0,D2 ; For GCR disk start at Address 0. <LW26>
@SetHead Move.b D3,D1 ; Head
Rol.b #2,D1 ; Position it.
Or.b D1,D0 ; Set it.
Move.w fDriveSelect(A1),D1 ; Drive select.
Or.b D1,D0 ; Set it.
Bsr WriteToFDC ; Send mode, head and drive.
Move.w csParam+18(A4),D0 ; Starting cylinder.
Bsr WriteToFDC ; Send it.
Move.b D3,D0 ; Head.
Bsr WriteToFDC ; Send it.
Move.b D2,D0 ; Starting sector.
Bsr WriteToFDC ; Send it.
Move.b fCode(A1),D0 ; Format byte (512 bytes/sector). <SM7>
Bsr WriteToFDC ; Send it.
Move SR,D0 ; Get and save the SR.
Btst #13,D0 ; Are we in Supervisor mode?
Bne.s @3 ; Yes? Then don't call _EnterSupervisorMode.
_EnterSupervisorMode ; Enter supervisor mode.
@3 Ori.w #$0700,SR ; Disable interrupts till done with I/O.
Move.w D0,-(Sp) ; Save status register.
Move.w D7,D0 ; Bytes to dump.
Lsr.w #8,D0 ; MSB.
Bsr WriteToFDC ; Send it.
Move.w D7,D0 ; Bytes to dump.
Bsr WriteToFDC ; Send LSB.
Lea Clock0,A5 ; Clock 0 table.
Clr.l D2 ; Bytes transferred.
Clr.l D7 ; Previous byte.
Moveq #31,D4 ; Clock register. <SM4>
Move.w #1,D6 ; Address increment if saving data.
Btst #0,D5 ; Saving data?
Bne.s @HaveDataBuf ; Yes? All set.
Move.w #0,D6 ; Don't increment address if not saving data.
Clr.w fCount(A1) ; Clear track cache.
Move.l fBuffer(A1),A3 ; Steal storage space.
@HaveDataBuf Btst #1,D5 ; Saving clocks?
Bne.s @HaveClockBuf ; Yes? Go set Address increment.
Move.w #0,D5 ; Don't increment address if not saving data.
Clr.w fCount(A1) ; Clear track cache.
Move.l fBuffer(A1),A2 ; Steal storage space.
Bra.s @Loop ; Go
@HaveClockBuf Move.w #4,D5 ; Address increment if clocks are save.
@Loop Asl.w #8,D7 ; get LSB bit of previous byte in position <SM4>
Move.l #$FFFF,D0 ; Timeout.
@ReadLoop Move.b fdcMSR(A0),D1 ; Main status.
Bpl.s @100 ; Not ready? Check timeout.
Btst #fExecute,D1 ; Still executing?
Beq.s @Status ; No? Then bail out.
Move.b fdcDATA(A0),D7 ; Yes? Read byte.
Move.b D7,(A3) ; Save byte.
Adda.w D6,A3 ; Increment Address.
Addq.l #1,D2 ; Bump counter.
Asl.l #1,D3 ; Shift clock bits. <SM4>
Andi.w #$1FF,D7 ; Get index of clock table ready <SM4>
Move.l #$FFFF,D0 ; Timeout.
@ReadLoop2 Move.b fdcMSR(A0),D1 ; Main status.
Bpl.s @200 ; Not ready? Check timeout.
Btst #fExecute,D1 ; Still executing?
Beq.s @Status ; No? Then bail out.
Move.b fdcDATA(A0),D0 ; Yes? Read byte.
Cmp.b (A5,D7.w),D0 ; Match? <SM4>
Beq.s @Next ; Yes? Then leave as 0.
Bset #0,D3 ; Set bad clock bit.
@Next Dbra D4,@Loop ; Next byte.
Moveq #31,D4 ; Clock register. <SM4>
Move.l D3,(A2) ; Save clock bits. <SM4>
Adda.w D5,A2 ; Increment Address.
Bra.s @Loop ; Next 32 bytes. <SM4>
@100 Subq.l #1,D0 ; Decrement counter.
Bne.s @ReadLoop ; Loop.
Bra.s @Status
@200 Subq.l #1,D0 ; Decrement counter.
Bne.s @ReadLoop2 ; Loop.
@Status Bsr ReadFromFDC
Move.b D0,fStatus0(A1)
Bsr ReadFromFDC
Move.b D0,fStatus1(A1)
Bsr ReadFromFDC
Move.b D0,fStatus2(A1)
Bsr ReadFromFDC
Move.b D0,fCylinder(A1)
Bsr ReadFromFDC
Move.b D0,fHead(A1)
Bsr ReadFromFDC
Move.b D0,fSector(A1)
Bsr ReadFromFDC
Move.b D0,fData(A1)
Move.w (Sp)+,SR ; Restore status register.
Rol.l D4,D3 ; Position clocks. <SM4>
@ClockEdge Cmp.w #31,D4 ; What is the count?
Bge.s @6 ; Full Count? Nothing to save.
Move.b D3,(A2)+ ; Save last clock bits.
Add.w #8, D4 ;
Bra.s @ClockEdge
@6 Bsr CheckError ; Get error code.
Move.w D1,D6 ; Error code.
Bne.s @DoneTrackDump ;
; Add code to get rid of zeros in the selfsync byte in GCR Mode <SM14>
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR?
Bgt.s @DoneTrackDump ; No? Great! All set.
Move.l csParam+4(A4),A3 ; Data buffer.
Beq.s @DoneTrackDump ; Nil? Great! Don't have to do anything.
Move.l A3,A2 ; Data buffer. <SM16>
Moveq #0,D0 ; Clear one register.
Moveq #0,D5 ; Clear another register.
Moveq #0,D1 ; Clear count register.
Move.l D2,D3 ; Need the number of bytes for count.
@9 Move.b (A3)+,D0 ; Get a byte of data.
Swap D0 ; Clear space for more bytes <SM20>
Move.w (A3),D0 ; Need three bytes. <SM20>
Lsl.l D1,D0 ; Shift out bytes that have been used
Btst #23,D0 ; Test MSB.
Bne.s @10 ; MSB = 1? All set.
And.l #$FFFFFF,D0 ; Make sure the upper bits are clear.
Cmp.l #$010000,D0 ; Is it a byte of zeroes.
Bge.s @11 ; Yes? go handle a byte of zeros.
Sub.l #1,D2 ; Decrement count. <SM20>
Sub.l #1,D3 ; Decrement count. <SM20>
Bne.s @9 ; Done yet? <SM20>
Bra.s @DoneTrackDump ; Out of here. <SM20>
@11 Add.w #1,D1 ; MSB = 0? Add to counter.
Lsl.l #1,D0 ; Shift 1 bit.
Btst #23,D0 ; Test MSB.
Beq.s @11 ; Still 0? Do it again.
@13 Cmp.w #8,D1 ; Have we shift 8 bits yet?
Blt.s @10 ; No? No need to do anything yet.
Sub.w #8,D1 ; Swap 8 in counter.
Adda.l #1,A3 ; For a one in the address.
Sub.l #1,D2 ; Update the real counter.
Bra.s @13
@10 Swap D0 ; Byte is now good.
Move.b D0,(A2)+ ; Restore good data.
Sub.l #1,D3 ; Decrement count.
Bgt.s @9 ;
; End of addition <SM14>
@DoneTrackDump
Move.l D2,csParam+12(A4) ; Save count.
Move.b #Specify,D0 ; Specify command.
Bsr WriteToFDC ; Send byte to FDC.
Moveq #0,D0 ; Step rate/head unload.
Bsr WriteToFDC ; Send byte to FDC.
Moveq #0,D0 ; Head load/DMA.
Bsr WriteToFDC ; Send byte to FDC.
@ExitTrackDump Rts ; Return.
Clock0 Dc.b $FF,$7F,$3F,$3F,$9F,$1F,$1F,$1F,$CF,$4F,$0F,$0F,$8F,$0F,$0F,$0F
Dc.b $E7,$67,$27,$27,$87,$07,$07,$07,$C7,$47,$07,$07,$87,$07,$07,$07
Dc.b $F3,$73,$33,$33,$93,$13,$13,$13,$C3,$43,$03,$03,$83,$03,$03,$03
Dc.b $E3,$63,$23,$23,$83,$03,$03,$03,$C3,$43,$03,$03,$83,$03,$03,$03
Dc.b $F9,$79,$39,$39,$99,$19,$19,$19,$C9,$49,$09,$09,$89,$09,$09,$09
Dc.b $E1,$61,$21,$21,$81,$01,$01,$01,$C1,$41,$01,$01,$81,$01,$01,$01
Dc.b $F1,$71,$31,$31,$91,$11,$11,$11,$C1,$41,$01,$01,$81,$01,$01,$01
Dc.b $E1,$61,$21,$21,$81,$01,$01,$01,$C1,$41,$01,$01,$81,$01,$01,$01
Dc.b $FC,$7C,$3C,$3C,$9C,$1C,$1C,$1C,$CC,$4C,$0C,$0C,$8C,$0C,$0C,$0C
Dc.b $E4,$64,$24,$24,$84,$04,$04,$04,$C4,$44,$04,$04,$84,$04,$04,$04
Dc.b $F0,$70,$30,$30,$90,$10,$10,$10,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $F8,$78,$38,$38,$98,$18,$18,$18,$C8,$48,$08,$08,$88,$08,$08,$08
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $F0,$70,$30,$30,$90,$10,$10,$10,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
Clock1 Dc.b $FE,$7E,$3E,$3E,$9E,$1E,$1E,$1E,$CE,$4E,$0E,$0E,$8E,$0E,$0E,$0E
Dc.b $E6,$66,$26,$26,$86,$06,$06,$06,$C6,$46,$06,$06,$86,$06,$06,$06
Dc.b $F2,$72,$32,$32,$92,$12,$12,$12,$C2,$42,$02,$02,$82,$02,$02,$02
Dc.b $E2,$62,$22,$22,$82,$02,$02,$02,$C2,$42,$02,$02,$82,$02,$02,$02
Dc.b $F8,$78,$38,$38,$98,$18,$18,$18,$C8,$48,$08,$08,$88,$08,$08,$08
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $F0,$70,$30,$30,$90,$10,$10,$10,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $FC,$7C,$3C,$3C,$9C,$1C,$1C,$1C,$CC,$4C,$0C,$0C,$8C,$0C,$0C,$0C
Dc.b $E4,$64,$24,$24,$84,$04,$04,$04,$C4,$44,$04,$04,$84,$04,$04,$04
Dc.b $F0,$70,$30,$30,$90,$10,$10,$10,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $F8,$78,$38,$38,$98,$18,$18,$18,$C8,$48,$08,$08,$88,$08,$08,$08
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $F0,$70,$30,$30,$90,$10,$10,$10,$C0,$40,$00,$00,$80,$00,$00,$00
Dc.b $E0,$60,$20,$20,$80,$00,$00,$00,$C0,$40,$00,$00,$80,$00,$00,$00
;******************************************************************************
; DiskCopy (Format and write in one pass).
;******************************************************************************
; local equates…
DiskCopy Link A6,#-ioQElSize ; Local storage. <LW10>
Move.l #NewAge32,A0 ; Base address of NewAge.
Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Correct record?
Beq.s @SetUp ; Yes? Then use it.
Move.l fNextRecord(A1),A1 ; Next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Correct record? <SM16>
Beq.s @SetUp ; Yes? Then use it.
@100 Move.w #nsDrvErr,D6 ; Assume no such drive.
Bra.w @InvalidDriveExit ; Out of here
@SetUp Move.w #paramErr,D6 ; Assume parameter error.
Move.l csParam+2(A4),A5 ; Pointer to data.
Move.b csParam+10(A4),D3 ; Format byte.
Move.b csParam+11(A4),D7 ; Do Verify.
Swap D7 ; Need lower half of D7
Move.w csParam(A4),D0 ; Format code.
Cmp.w #3,D0 ; 720K MFM format? <SM4>
Beq.s @CheckLDMFM ; Check for LD media + correct drive. <SM4>
Cmp.w #2,D0 ; GCR format?
Beq.s @CheckGCR ; Check for LD media.
Cmp.w #1,D0 ; Better be 1.
Bne @ExitFormatCopy ; No? Then we're out-a-here.
Lea FormatTable,A2 ; Assume LD media (then 400K GCR). <SM4>
Cmp.w #mLD,fMediaType(A1) ; LD?
Beq.s @InitRegisters ; Yes? Then prepare to format.
Lea SuperDrvTable,A2 ; Assume HD media (then 1.4 MFM).
Cmp.w #mHD,fMediaType(A1) ; HD?
Beq.s @InitRegisters ; Yes? Then prepare to format.
Lea TyphoonTable,A2 ; Must be ED media (then 2.8 MFM).
Bra.s @InitRegisters ; Prepare to format.
@CheckLDMFM Cmp.w #fddMac800,fDriveType(A1) ; 800K drive installed?
Beq @ExitFormatCopy ; Yes? Then can't support MFM.
Cmp.w #mLD,fMediaType(A1) ; Low density disk inserted?
Bne @ExitFormatCopy ; No? Then param error.
Lea SuperDrvTable+12,A2 ; Yes? Then point to format description.
Bra.s @InitRegisters ; Prepare for format. <SM4>
@CheckGCR Cmp.w #mLD,fMediaType(A1) ; Low density disk inserted? <SM4>
Bne @ExitFormatCopy ; No? Then param error. <SM4>
Lea FormatTable+12,A2 ; Yes? Then point to format description.
@InitRegisters Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #$0,D0 ; Standard.
Cmp.w #f2880K,ftFormatCode(A2) ; Extended density?
Bne.s @0 ; No? Then horizontal mode.
Moveq #vertical,D0 ; Yes? Set vertical mode.
@0 Bsr WriteToFDC ; Send it.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetDriveGCR,D0 ; Set drive mode to GCR.
Moveq #(dr500 << DataRateOffset),D1 ; Data rate.
Cmp.w #fUnknownGCR,ftFormatCode(A2) ; GCR format?
Ble.s @1 ; Yes? Then set it.
Move.b #SetDriveMFM,D0 ; Set drive to MFM.
Moveq #(dr500 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Date rate/pre-comp for HD.
Cmp.w #f1440K,ftFormatCode(A2) ; Double density?
Ble.s @1 ; Yes? Then set it.
Moveq #(dr1000 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Must be extended density.
@1 Move.b D1,fdcDRR(A0) ; Set data rate/pre-comp.
Bsr WriteToFDC ; Send mode byte.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send it.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Waitx Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Done?
Bne.s @Donex ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Waitx ; Loop
Move.w #noNybErr,fResult(A1) ; Error?
If Break Then
_debugger
EndIf
@Donex Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w fResult(A1),D6 ; Error?
Bne @ExitFormatCopy ; Yes? Out of here.
Bsr Track0 ; Recalibrate.
Move.w fResult(A1),D6 ; Error?
Bne @ExitFormatCopy ; Yes? Out of here.
Moveq #0,D2 ; Starting cylinder number.
Move.w #0,D7 ; Init sync group flag.
Move.b ftSectors(A2),-3(A6); Number of sectors/track.
Move.b ftFormatByte(A2),-2(A6) ; Format code.
Move.b ftGap3Length(A2),D7 ; Gap3 length or number of sync groups.
Moveq #(MFMCylndrs -1),D5 ; Tracks/zone for MFM (1 zone).
Move.b #FormatWrite,-1(A6) ; FormatTrack command.
Lea MFMInterleave,A4 ; Interleave table.
Cmp.b #10,-3(A6) ; Sector count equal 10?
Bne.s @CylinderLoop ; No? Then MFM.
Move.b #12,-3(A6) ; Starting sectors/track for GCR.
Moveq #(GCRCylndrs -1),D5 ; Tracks/zone for GCR (5 zones).
Bclr.b #fFM,-1(A6) ; Clear MFM flag.
Move.b D3,-2(A6) ; Format code.
Lea Zone1_2,A4 ; 2:1 interleave table.
Cmp.b #formatGCR4_1,D3 ; 4:1 interleave?
Bne.s @CylinderLoop ; No? Then we have the right table.
Lea Zone1_4,A4 ; Yes? 4:1 interleave table.
@CylinderLoop Moveq #0,D3 ; Starting head.
Bsr SeekToTrack ; Seek to cylinder.
Move.w fResult(A1),D6 ; Seek error? <LW18>
Bne @ExitFormatCopy ; If so report it. <LW18>
@SideLoop Move.b -1(A6),D0 ; FormatWrite command. <SM4>
Bsr WriteToFDC ; Write command.
Move.b fDriveSelect(A1),D0 ; Drive select.
Tst.w D3 ; Check side.
Beq.s @4 ; Side 0? Then all set.
Bset #fHd,D0 ; Set “side 1” flag.
@4 Bsr WriteToFDC ; Write head/drive.
Move.b -2(A6),D0 ; 512 bytes/sector (format code).
Bsr WriteToFDC ; Write bytes/sector.
Move.b -3(A6),D0 ; Sectors/track.
Bsr WriteToFDC ; Write sectors/track.
Move.l fBuffer(A1),A3 ; Pointer to buffer.
Moveq #0,D0 ; Clear sector loop counter.
Move.b -3(A6),D0 ; Sectors/track.
Subq.w #1,D0 ; For looping.
Move.l A4,D6 ; Keep copy of interleave table.
@10 Move.b D2,(A3)+ ; Track.
Move.b D3,(A3)+ ; Side.
Btst #fFM,-1(A6) ; Is this a MFM format? <LW7>
Bne.s @Sector ; Yes? The give the correct Sector number. <LW7>
Btst #15,D7 ; Is this the real format? <LW7>
Bne.s @Sector ; Yes? Then give the correct Sector number. <LW7>
Move.b #$3f,(A3)+ ; Give it a bogus Sector number <LW7>
Bra.s @FormatByte ; And Continue... <LW7>
@Sector Move.b (A4),(A3)+ ; Sector.
@FormatByte Move.b -2(A6),(A3)+ ; Format byte.
Move.w #127,D4 ; 512 bytes/sector but doing long transfer.
Moveq #0,D1 ; Init offset register.
Move.b (A4)+,D1 ; Sector number.
Btst #fFM,-1(A6) ; Formatting MFM?
Beq.s @14 ; no? then no need to do sub.
Sub.b #1,D1 ; mfminterleave is 1 base.
@14 Asl.w #8,D1 ; * 256.
Asl.w #1,D1 ; * 2 (* 512).
@11 Move.l (A5,D1.w),(A3)+ ; long to send.
Addq.w #4,D1 ; Next long.
Dbra D4,@11 ; Loop for one sector of data
Dbra D0,@10 ; Loop for one track.
Moveq #0,D0 ; Clear sector loop counter.
Move.b -3(A6),D0 ; Sectors/track.
Asl.l #2,D0 ; 4 header param/ sector.
Move.l D0,D1 ; Save it.
Asl.l #7,D0 ; 512 data byte/sector.
Add.l D0,D1 ; Bytes to transfer.
Move.l #pscControl32,A3 ; PSC control register.
Move.w #(1 << pscPause) | \ ;
(1 << pscSense), \ ;
(A3) ; Pause PSC.
@waitfrozen Move.w (A3), D0 ;
Btst.l #pscFrozen, D0 ; Test forzen bit.
Beq.s @waitfrozen ; Check that pause bit is frozen.
Move.w (A3),D0 ; Control setting.
And.w #$1,D0 ; Get set.
Asl.w #4,D0 ; Calculate offset to correct set.
Move.l #pscSet032,A4 ; DMA register set.
Move.l D1,pscCount(A4,D0.w) ; Set count. <SM21>
Move.l fBuffer(A1),pscAddress(A4,D0.w) ; Set address.
Move.w #(1 << pscDir) | \ ;
(0 << pscSense), \ ;
pscStatus(A4,D0.w) ; Set direction to write.
Move.w #(1 << pscEnable) | \ ;
(1 << pscSense), \ ;
pscStatus(A4,D0.w) ; Enable it.
Move.w #(1 << pscPause) | \ ;
(0 << pscSense), \ ;
(A3) ; Un-pause.
Move.l D6,A4 ; Restore interleave table.
Move.w #1,fResult(A1) ; Set result to “in progress”.
Move.b D7,D0 ; GCR sync groups or MFM Gap3 length.
Btst #fFM,-1(A6) ; Is this a MFM format? <LW7>
Bne.s @WriteSync ; Yes? The just write GAP3 length. <LW7>
Btst #15,D7 ; Is this the real format? <LW7>
Bne.s @WriteSync ; Yes? Then write the correct number of Sync Group. <LW7>
Move.b #$3f,D0 ; Give it a large number of Sync Group for Bogus format. <LW7>
@WriteSync Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Write Gap3 length (or sync groups).
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #2,D1 ; DBRA/4 Millisecond.
@Wait Bsr GetResult ; Check for interrupt. <SM23>
Cmp.w #0,fResult(A1) ; Result.
Ble.s @DoneDMA ; Done? Out of here.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
If Break Then
_debugger
EndIf
Bsr ResetFDC ; If timeout then something horrible happened. <SM20>
Move.w #noNybErr,fResult(A1) ; Report as timeout error. <SM20>
@DoneDMA Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.w #(1 << pscSWReset) | \ ;
(1 << pscSense), \ ;
(A3) ; Reset channel.
Move.w fResult(A1),D6 ; Check error. <LW4>
Bne @ExitFormatCopy ; <LW4>
Btst #fFM,-1(A6) ; Formatting MFM? <SM4>
Bne.s @NextSide ; Yes? Then do next side.
Btst #15,D7 ; Was this pass real or just erasing the disk? <LW7>
Bne.s @ClearFlag ; Valid Format? Then clear flag and continue. <LW7>
Bset #15,D7 ; Set flag. <LW7>
Beq @SideLoop ; And Do the valid format. <LW7>
@ClearFlag Bclr #15,D7 ; <LW7>
@NextSide Moveq #0,D0 ; Init register.
Move.b -3(A6),D0 ; Sectors/track.
Asl.w #8,D0 ; * 256.
Asl.w #1,D0 ; * 2 (* 512).
Adda.w D0,A5 ; Bump data pointer.
Move.b ftSides(A2),D0 ; Flags/Sides.
And.b #$F,D0 ; Sides.
Cmp.b #1,D0 ; Single sided?
Beq.s @NextCylinder ; Yes? Then do next cylinder.
Addq.w #1,D3 ; Next side.
Cmp.w #1,D3 ; Side 1?
Beq @SideLoop ; Yes? Then do it.
@NextCylinder Addq.w #1,D2 ; Next cylinder.
Dbra D5,@CylinderLoop ; Cylinders left in this zone? Do it.
Adda.w #itNextZone,A4 ; Next interleave zone.
Subq.b #1,-3(A6) ; Decrement sectors/cylinder.
Moveq #15,D5 ; Reset cylinders/zone.
Cmp.w #DiskCylndrs,D2 ; Done?
Blt @CylinderLoop ; No? Then do it.
Bsr Track0 ; Recalibrate. <SM4> ws
Clr.b fCylinder(A1) ; Set track to 0. <SM4> ws
Moveq #noErr,D6 ; Indicate no error.
Move.l fDriveQueue(A1),A3 ; Pointer to drive queue.
Move.w ftFormatCode(A2),fFormat(A1) ; Set media format.
Move.w ftBlocks(A2),dQDrvSz(A3) ; Number of blocks.
Move.b #$FF,-1(A3) ; Non single-sided. <LW14>
Move.b #1,-3(A3) ; Set “Disk in place” flag.
Cmp.w #f400K,fFormat(A1) ; 400K GCR?
Bne.s @VerifyDisk ; No? Then double-sided.
Clr.b -1(A3) ; Single-sided.
Swap D7 ; Get do verify flag.
Tst.w D7 ;
Beq.s @ExitFormatCopy ; Don't do verify.
@VerifyDisk Move.l NewAgeVars,A3 ; DCE pointer.
Moveq #1,D3 ; Head.
Moveq #0,D2 ; Starting cylinder.
Moveq #0,D5 ; Starting sector number.
Moveq #0,D6 ; Init register.
Move.b ftSectors(A2),D6 ; Number of sectors/track.
Moveq #(MFMCylndrs -1),D7 ; Tracks/zone for MFM (1 zone).
Move.l fBuffer(A1),A2 ; Buffer.
Clr.l fCount(A1) ; Invalidate cache <SM20>
Lea -ioQElSize(A6),A4 ; Parameter block.
Move.w fDriveNum(A1),ioDrvNum(A4)
Cmp.b #10,D6 ; Sector count equal 10?
Bne.s @DoVerify ; No? Then MFM. <LW10>
Moveq #12,D6 ; Starting sectors/track for GCR.
Moveq #(GCRCylndrs -1),D7 ; Tracks/zone for GCR (5 zones).
@DoVerify Move.b #VerifyRetry,fRetrySeed(A1) ; Change the retry Count <SM30>
Move.b #VerifyRetry,fRetries(A1) ; Reset counter. <SM30>
@VerifyLoop Clr.l ioActCount(A4) ; Init count. <LW10>
Move.w D6,D4 ; Sectors/track. <LW10>
IF MTMode THEN
Cmp.w #f400K,fFormat(A1) ; Single sided? <LW10>
Beq.s @0 ; <LW10>
Asl.w #1,D4 ; Do both sides if multi-track. <LW10>
@0
ENDIF
Movem.l A2-A5/D2-D7,-(Sp) ; Save registers. <LW10>
Bsr DoRead ; Read track (or cylinder). <LW10>
Movem.l (Sp)+,A2-A5/D2-D7 ; Restore registers. <LW10>
Tst.w fResult(A1) ; Any errors? <LW10>
Bne.s @CopyError ; Yes? Then leave. <LW10>
Add.w D4,D5 ; Next starting sector. <LW10>
IF NOT MTMode THEN
Cmp.w #f400K,fFormat(A1) ; Single sided? <LW10>
Beq.s @ReadNextCylinder ; Yes? Then do next cylinder. <LW10>
Subq.w #1,D3 ; Next side. <LW10>
Neg.w D3 ; Still positive? <LW10>
Beq.s @VerifyLoop ; Yes? Then do it. <LW10>
ENDIF
@ReadNextCylinder
Addq.w #1,D2 ; Next cylinder. <LW10>
Dbra D7,@VerifyLoop ; Cylinders left in this zone? Do it. <LW10>
Subq.w #1,D6 ; Decrement sectors/cylinder. <LW10>
Moveq #(GCRCylndrs -1),D7 ; Reset cylinders/zone. <LW10>
Cmp.w #DiskCylndrs,D2 ; Done? <LW10>
Blt.s @VerifyLoop ; No? Then do it. <LW10>
Move.w fResult(A1),D6 ; <LW10>
@ExitFormatCopy Move.l Ticks,fLastAccess(A1)
Move.b #RetryCount,fRetrySeed(A1) ; Reset the retry Count <SM30>
Move.b #RetryCount,fRetries(A1) ; Reset counter. <SM30>
Clr.w fCount(A1) ; Void buffer.
@InvalidDriveExit
Unlk A6 ; Kill local storage.
Rts ; And leave.
@CopyError Move.w fResult(A1),D6 ; <LW4>
Bra.s @ExitFormatCopy ; <LW4>
;------------------------------------------------------------------------------
; Routine: Status
; Inputs: A0 -> Parameter block.
; A1 -> DCE.
; Outputs: D0 -> 0 - OK, ~0 - Error.
; Function: Return info for status requests.
;------------------------------------------------------------------------------
StatusRegs REG A0-A4/D3-D7 ; Registers abused.
Status
Movem.l StatusRegs,-(Sp) ; Scratch registers.
Movea.l A0,A4 ; Save parameter block.
Movea.l NewAgeVars,A3 ; DCE pointer.
Moveq #statusErr,D6 ; Assume failure.
Move.w csCode(A4),D0 ; CSCode.
Lea StatusVectors,A0 ; Vector table.
@Loop Cmp.w (A0),D0 ; Match?
Beq.s @CallIt ; Yes? Then call it.
Tst.l (A0)+ ; Next vector.
Bne.s @Loop ; Does it exist? Then check it.
Bra.s @ExitStatus ; No? Then leave with error.
@CallIt Move.w 2(A0),D0 ; Offset.
Beq.s @ExitStatus ; Leave if no routine.
Jsr StatusVectors(D0) ; Call it.
@ExitStatus Move.w D6,D0 ; Call result.
Movem.l (Sp)+,StatusRegs ; Restore registers.
Move.w D0,ioResult(A0) ; Set result value.
Move.w ioTrap(A0),D1 ; Trap called.
Btst #noQueueBit,D1 ; Called immediately?
Bne.s @2 ; Yes? Then leave via an RTS.
Tst.w D0 ; Completed?
Ble.s @1 ; Yes? Then go through IODone.
Btst #asyncTrpBit,D1 ; Called asynchronously?
Bne.s @2 ; Yes? Then leave via an RTS.
@1 Move.l JIODone,-(Sp) ; Vector to IODone.
@2 Rts ; Return.
StatusVectors Dc.w 06,FormatList - StatusVectors
Dc.w 08,DriveStatus - StatusVectors
; Apple use only routines…
Dc.w 10,MFMStatus - StatusVectors
Dc.w 17494,Duplicator - StatusVectors
Dc.w 21072,FloppyInfo - StatusVectors
Dc.w 21315,FormatByte - StatusVectors
Dc.w 0, 0
;******************************************************************************
; Return format list.
;******************************************************************************
FormatList Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to record.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @BuildTable ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Match? <SM16>
Beq.s @BuildTable ; Yes? Then check for drive. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Bra.s @ExitFormatList ; No record? Then leave.
@BuildTable Move.w #offLinErr,D6 ; Assume no disk.
Tst.w fFormat(A1) ; Disk in?
Beq.s @ExitFormatList ; No? Then leave with error.
Move.w #paramErr,D6 ; Assume parameter error.
Move.w csParam(A4),D0 ; Number of formats to return.
Subq.w #1,D0 ; For looping.
Bmi.s @ExitFormatList ; -? Then param error.
Moveq #noErr,D6 ; No error.
Move.l csParam+2(A4),A0 ; Table.
Clr.w csParam(A4) ; Init number of entries returned.
Lea FormatTable,A2 ; Pointer to format table.
Lea AppleDrv,A3 ; Assume AppleDrive installed.
Cmp.w #fddMac800,fDriveType(A1) ; 800K drive installed?
Beq.s @FormatLoop ; Yes? Then we know end of table.
Lea LowDensity,A3 ; Assume low denisty media inserted.
Cmp.w #mLD,fMediaType(A1) ; Low denisty disk?
Beq.s @FormatLoop ; Yes? Then all GCR & 720K supported.
Lea HighDensity,A3 ; Assume high denisty media inserted.
Cmp.w #mHD,fMediaType(A1) ; High denisty disk?
Beq.s @FormatLoop ; Yes? Then only HD format allowed.
Lea ExtendedDensity,A3 ; Must be extended density media.
@FormatLoop Move.w (A3)+,D3 ; Offset to format.
Bmi.s @ExitFormatList ; -? Then end of list.
Move.l (A2,D3.w),(A0)+ ; Number of blocks.
Move.l ftFlags(A2,D3.w),D2 ; Flags.
Move.l ftFormatByte(A2,D3.w),D1 ; Format flag.
Cmp.w fFormat(A1),D1 ; Match?
Bne.s @0 ; No? The disk doesn't have this format.
Bset #30,D2 ; Yes? Then disk has this format.
@0 Move.l D2,(A0)+ ; Install flags.
Addq.w #1,csParam(A4) ; Bump count.
@1 Dbra D0,@FormatLoop ; Loop. <SM16>
@ExitFormatList Rts ; Leave.
AppleDrv Dc.w 0,12,24,-1,-1 ; Apple drive can support all GCR.
LowDensity Dc.w 0,12,24,48,-1 ; SuperDrive/Typhoon LD: GCR, 720K MFM.
HighDensity Dc.w 36,-1,-1,-1,-1 ; SuperDrive/Typhoon HD: 1.4 MFM.
ExtendedDensity Dc.w 60,-1,-1,-1,-1 ; Typhoon ExtendedDensity: 2.8 MFM.
FormatTable Dc.l 0800,$810A0050 ; 400K GCR 2:1 Interleave.
Dc.b $12,$8 ; Format byte, sync groups.
Dc.w f400K ; Format code.
Dc.l 1600,$820A0050 ; 800K GCR 2:1 Interleave.
Dc.b $22,$8 ; Format byte, sync groups.
Dc.w f800K ; Format code.
Dc.l 1600,$A20A0050 ; ProDOS GCR 4:1 Interleave.
Dc.b $24,$8 ; Format byte, sync groups.
Dc.w fProDOS ; Format code.
SuperDrvTable Dc.l 2880,$d2120050 ; 1.4 MFM. <LW10>
Dc.b $02,$65 ; Format byte, Gap3 length.
Dc.w f1440K ; Format code.
Dc.l 1440,$82090050 ; 720K MFM.
Dc.b $02,$50 ; Format byte, Gap3 length.
Dc.w f720K ; Format code.
TyphoonTable Dc.l 5760,$d2240050 ; 2.8 MFM. <LW10>
Dc.b $02,$54 ; Format byte, Gap3 length.
Dc.w f2880K ; Format code.
EndOfTable Dc.l 0,0,0 ; End of table.
;******************************************************************************
; Return drive status.
;******************************************************************************
DriveStatus Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @GetRecord ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Match? <SM16>
Beq.s @GetRecord ; Yes? Then check for drive. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Cmp.w #2,D0 ; Must accept drive number 1 and 2.
Bgt.s @ExitDrvStatus ; Unknown drive number? Then leave.
Cmp.w #0,D0 ; Must accept drive number 1 and 2.
Ble.s @ExitDrvStatus ; Unknown drive number? Then leave.
Moveq #noErr,D6 ; Indicate no error.
Lea csParam(A4),A0 ; Record.
; This is the data return for an uninstalled drive.
Clr.l (A0)+ ; Track at zero. Not write protect. No disk.
Move.w #$FFFF,(A0)+ ; No drive installed. Two side drive not installed.
Clr.l (A0)+ ; No queue link.
Clr.w (A0)+ ; Dummy queue?
Move.w D0,(A0)+ ; Drive number.
Move.w #$FFFB,(A0)+ ; Floppy drive ref number.
Clr.w (A0)+ ; File System ID.
Move.w #$FFFF,(A0)+ ; 2 sided format. New interface.
Clr.w (A0)+
Bra.s @ExitDrvStatus ; Done
@GetRecord Move.l fDriveQueue(A1),A3 ; Drive queue.
Lea csParam(A4),A0 ; Record.
Clr.b (A0)+ ; High byte of track.
Move.b fCylinder(A1),(A0)+ ; Track.
Move.b -4(A3),(A0)+ ; Write protect.
Move.b -3(A3),(A0)+ ; Disk in place.
Move.b #1,(A0)+ ; Installed.
Move.b #$FF,(A0)+ ; 2-Sided drive.
Move.l qLink(A3),(A0)+
Move.w qType(A3),(A0)+
Move.w dQDrive(A3),(A0)+
Move.w dQRefNum(A3),(A0)+
Move.w dQFSID(A3),(A0)+
Move.b -1(A3),(A0)+ ; Sides.
Move.b #$FF,(A0)+ ; Assume new interface.
Cmp.w #f400K,fFormat(A1) ; 400K GCR? <LW14>
Bne.s @1 ; No? Then double-sided. <LW14>
Move.b #0,-1(A0) ; Old interface. <LW14>
@1 Move.w fSoftErrors(A1),(A0)+ ; Soft errors.
Moveq #noErr,D6 ; Indicate no error.
@ExitDrvStatus Rts ; And leave.
;******************************************************************************
; Return MFM status.
;******************************************************************************
MFMStatus Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @SetStatus ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Match? <SM16>
Beq.s @SetStatus ; Yes? Then check for drive. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Bra.s @ExitMFMStatus ; No record? Then leave.
@SetStatus Clr.b csParam(A4) ; Assume 800K floppy.
Cmp.w #fddMac800,fDriveType(A1) ; Check drive type.
Ble.s @0 ; 800K or less?
Move.b #-1,csParam(A4) ; Assume SuperDrive.
Cmp.w #fddSuperDrive,fDriveType(A1)
Beq.s @0 ; SuperDrive?
Move.b #-2,csParam(A4) ; Must be a Typhoon.
@0 Clr.b csParam+1(A4) ; Assume GCR format.
Cmp.w #fUnknownGCR,fFormat(A1) ; Last GCR format.
Ble.s @1 ; GCR?
Move.b #-1,csParam+1(A4) ; Must be MFM.
@1 Move.w fFormat(A1),D0 ; Drive format.
Sub.w #f720K,D0 ; Make 0 based.
Neg.w D0 ; Negate it.
Move.b D0,csParam+2(A4) ; Disk format.
Move.b #-3,csParam+3(A4) ; NewAge.
Moveq #noErr,D6 ; Indicate no error.
@ExitMFMStatus Rts ; And leave.
;******************************************************************************
; Return duplicator version.
;******************************************************************************
Duplicator Move.w #$0410,csParam(A4) ; Return min. duplicator version.
Moveq #noErr,D6 ; Indicate no error.
Rts ; And leave.
;******************************************************************************
; Return floppy info record.
;******************************************************************************
FloppyInfo Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @SetPointer ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Match? <SM16>
Beq.s @SetPointer ; Yes? Then check for drive. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Bra.s @ExitFloppyInfo ; No record? Then leave.
@SetPointer Move.l A1,csParam(A4) ; Return pointer to floppy info record.
Moveq #noErr,D6 ; Set no error.
@ExitFloppyInfo Rts ; Leave.
;******************************************************************************
; Return last format byte read.
;******************************************************************************
FormatByte Move.w ioDrvNum(A4),D0 ; Drive number.
Move.l dCtlStorage(A3),A1 ; Pointer to floppy info.
Cmp.w fDriveNum(A1),D0 ; Match?
Beq.s @GetByte ; Yes? Then check for drive.
Move.l fNextRecord(A1),A1 ; Point to next record.
Beq.s @100 ; <LW17>
Cmp.w fDriveNum(A1),D0 ; Match? <SM16>
Beq.s @GetByte ; Yes? Then check for drive. <SM16>
@100 Move.w #nsDrvErr,D6 ; Assume “No such drive” error.
Bra.s @ExitFormatByte ; No record? Then leave.
@GetByte Move.b fData(A1),csParam(A4) ; Set format code.
Moveq #noErr,D6 ; Set no error.
@ExitFormatByte Rts ; Leave.
IF noClose Then
;------------------------------------------------------------------------------
; Routine: Close
; Inputs: A0 -> Parameter block.
; A1 -> DCE.
; Outputs: D0 -> 0 - OK.
; Function: The Floppy Driver should not be close. Return error code.
;------------------------------------------------------------------------------
Close Moveq #closErr,D0 ; Indicate error.
Move.l JIODone,-(Sp) ; Vector to IODone.
Rts ; And call it.
ELSE
;------------------------------------------------------------------------------
; Routine: Close
; Inputs: A0 -> Parameter block.
; A1 -> DCE.
; Outputs: D0 -> 0 - OK.
; Function: Close the driver releasing any memory used.
;------------------------------------------------------------------------------
CloseRegs REG A0-A3/D3-D4 ; Registers abused.
Close Movem.l CloseRegs,-(Sp) ; Scratch registers.
Movea.l NewAgeVars,A1 ; DCE.
Clr.l VIA2DT+(5*4) ; Clear handler.
Move.b #DisableFDCInt,VIA2IER; Disable interrups. <SM1> RLM
Movea.l dCtlStorage(A1),A2 ; Floppy info record.
Move.w dCtlRefNum(A1),D4 ; Driver RefNum.
@Loop Move.l fNextRecord(A2),D3 ; Pointer to next record.
Move.l fBuffer(A2),D0 ; Buffer?
Beq.s @0 ; No? Then kill record.
Move.l D0,A0 ; Buffer pointer.
_DisposPtr ; Free it.
@0 Move.l A2,A0 ; Pointer to record.
_DisposPtr
Move.l D3,A2 ; Assume there is another record.
Tst.l D3 ; Is there another record?
Bne.s @Loop ; Yes? Then kill it.
@1 Lea DrvQHdr+2,A0 ; Pointer to first drive.
@DrvLoop Move.l A0,A1 ; Save current drive.
Move.l (A0),D0 ; Is there a drive?
Beq.s @ExitClose ; No? Then we're done.
Move.l D0,A0 ; Pointer to drive queue.
Cmp.w dQRefNum(A0),D4 ; Is this our drive?
Bne.s @DrvLoop ; No? Then check next drive.
Lea DrvQHdr,A1 ; Drive queue header.
_Dequeue ; Remove it from the queue.
Tst.l -(A0) ; Point to fron of flags.
_DisposPtr ; Kill queue record.
Bra.s @1 ; Loop till done.
@ExitClose Movem.l (Sp)+,CloseRegs ; Restore registers.
Moveq #noErr,D0 ; Indicate no error.
Move.l JIODone,-(Sp) ; Vector to IODone.
Rts ; And call it.
ENDIF
;------------------------------------------------------------------------------
; Routine: SetUpFDC
; Inputs: A4 -> Parameter block.
; Outputs: A0 -> FDC base address.
; A1 -> Floppy info record.
; Function: Set the FDC to the correct mode of opertion.
; Called By: Prime, Verify.
;------------------------------------------------------------------------------
SetUpFDC Move.l A2,-(Sp) ; Save A2.
Move.l #NewAge32,A0 ; Base address of NewAge.
Move.l NewAgeVars,A1 ; Pointer to DCE.
Move.l dCtlStorage(A1),A1 ; Floppy info records.
Move.w ioDrvNum(A4),D0 ; Drive number.
Cmp.w fDriveNum(A1),D0 ; Correct record?
Beq.s @SetUp ; Yes? Then use it.
Move.l fNextRecord(A1),A1 ; Next record.
@SetUp Move.l fDriveQueue(A1),A2 ; Drive queue. <LW26>
Cmp.b #1,-3(A2) ; First access to this floppy? <LW26>
Beq @SetUp2 ; Yes? Then need to do everything. <LW26>
Tst.b fMotor(A1) ; Motor on? <LW26>
Bne @ExitSetUp ; Yes? Then done. <LW26>
Bsr EnableMotor ; Turn motor on. <LW26>
Bra @ExitSetUp ; Done. <LW26>
@SetUp2 Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetEnableOn,D0 ; Set enable command.
Bsr WriteToFDC ; Send it.
Move.w fDriveSelect(A1),D0 ; Drive number.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Enable the drive.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Wait Bsr SenseInterrupt ; Go check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change.
Bne.s @Changed ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Bsr ResetFDC ; Try resetting FDC.
Move.w #noNybErr,fResult(A1) ; Error?
If Break Then
_debugger
EndIf
@Changed Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
; Move.l fDriveQueue(A1),A2 ; Drive queue.
; Cmp.b #1,-3(A2) ; First access to this floppy?
; Bne @SetMode ; No? Then we already know what it is.
Move.b #2,-3(A2) ; Yes? Then set flag.
Bsr Track0 ; And recalibrate.
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #SenseDrvStatus,D0 ; Sense drive status command.
Bsr WriteToFDC ; Send command.
Move.b fDriveSelect(A1),D0 ; Drive ID.
Bsr WriteToFDC ; Send command.
Bsr ReadFromFDC ; Read Status3.
Move.b D0,fStatus3(A1) ; Save it.
Move.b #1,fRetries(A1) ; Set retry count.
Move.w #mLD,fMediaType(A1) ; Assume low density.
Btst #7,D0 ; Low density bit set?
Bne.s @StartMotor ; Yes? Then start motor.
Move.w #mHD,fMediaType(A1) ; Assume high density.
Btst #1,D0 ; Sel media bit set?
Bne.s @StartMotor ; Yes? Then high density.
Move.w #mED,fMediaType(A1) ; Must be extended density.
@StartMotor Bsr EnableMotor ; Turn motor on.
Tst.w fResult(A1) ; Get error code.
Bne @ExitSetUp ; Error? Out of here.
Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #$0,D0 ; Standard.
Bsr WriteToFDC ; Send it.
@GCRRetry Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetDriveGCR,D0 ; Set drive mode to GCR.
Bsr WriteToFDC ; Send it.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send it.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Wait0 Bsr SenseInterrupt ; Go check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change.
Bne.s @Changed0 ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait0 ; Loop
Bra.s @0 ; Error. Go reset.
@Changed0 Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #(dr500 << DataRateOffset),fdcDRR(A0) ; Set data rate.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #ReadGCRID,D0 ; Command.
Bsr WriteToFDC ; Send command.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Write head/drive.
Bne.s @0 ; Fail? Reset.
Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond. <SM4> ws
@Wait1 Bsr GetResult ; Go check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change.
Bne @CheckResult ; Change? Then check it.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait1 ; Loop until it changes.
@0 Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
If Break Then
_debugger
EndIf
Bsr ResetFDC ; Try resetting FDC.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <LW8>
Move.b #-1,fStatus0(A1) ; Set flag. <LW8>
Moveq #0,D1 ; Init counter. <LW8>
Move.w TimeDBRA,D1 ; DBRA/Millisecond. <LW8>
Asl.l #6,D1 ; DBRA/64 Millisecond. <LW8>
@WaitGCRInt Bsr SenseInterrupt ; Check for interrupt. <LW8>
Cmp.b #-1,fStatus0(A1) ; Done? <LW8>
Bne.s @GCRResetInt ; Change? Then Get out. <LW8>
Subq.l #1,D1 ; Decrement counter. <LW8>
Bne.s @WaitGCRInt ; Loop <LW8>
Move.w #noNybErr,fResult(A1) ; Set flag
@GCRResetInt Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <LW8>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #-1,fStatus0(A1) ; Set flag. <LW8>
Move.b #SetEnableOn,D0 ; Set enable command. <LW8>
Bsr WriteToFDC ; Send it. <LW8>
Move.w fDriveSelect(A1),D0 ; Drive number. <LW8>
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <LW8>
Bsr WriteToFDC ; Enable the drive. <LW8>
Moveq #0,D1 ; Init counter. <LW8>
Move.w TimeDBRA,D1 ; DBRA/Millisecond. <LW8>
Asl.l #8,D1 ; DBRA/256 Millisecond. <LW8>
@WaitGCREnable Bsr SenseInterrupt ; Go check for interrupt. <LW8>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change. <LW8>
Bne.s @GCREnable ; Change? Then Get out. <LW8>
Subq.l #1,D1 ; Decrement counter. <LW8>
Bne.s @WaitGCREnable ; Loop <LW8>
Move.w #noNybErr,fResult(A1) ; Set flag
@GCREnable Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <LW8>
Clr.b fMotor(A1) ; Clear flag. <LW8>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #$0,D0 ; Standard.
Bsr WriteToFDC ; Send it.
Subq.b #1,fRetries(A1) ; Retry?
Bpl @GCRRetry ; Yes? Then do it.
Bra.s @MFM ; No? Then try MFM.
@CheckResult Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Tst.w fResult(A1) ; Check error code.
Bne.s @MFM ; Error? Then check for MFM disk.
Move.w #f400K,fFormat(A1) ; Assume 400K GCR.
Move.b fData(A1),D0 ; Data code.
Cmp.b #$02,D0 ; 400K format (SuperDrive bug)?
Beq @SetQueue ; Yes? Then setup drive queue.
Cmp.b #formatGCR400K,D0 ; 400K format (The real one)?
Beq @SetQueue ; Yes? Then setup drive queue.
Move.w #f800K,fFormat(A1) ; Assume 800K GCR (Mac).
Cmp.b #formatGCR2_1,D0 ; 800K format?
Beq @SetQueue ; Yes? Then setup drive queue.
Move.w #fProDOS,fFormat(A1) ; Assume ProDOS format.
Cmp.b #formatGCR4_1,D0 ; Apple II format?
Beq @SetQueue ; Yes? Then setup drive queue.
Move.w #fUnknownGCR,fFormat(A1) ; Set “unknown” flag.
Beq @SetQueue ; Yes? Then setup drive queue.
@MFM Cmp.w #fddSuperDrive,fDriveType(A1) ; At least a SuperDrive?
Blt @Blank ; No? Then can't check MFM.
Clr.b fLastSector(A1) ; Set last sector to zero.
Move.b #1,fRetries(A1) ; Set retry count.
@MFMRetry Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetDriveMFM,D0 ; Set drive mode to MFM.
Bsr WriteToFDC ; Send it.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send it.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Wait2 Bsr SenseInterrupt ; Go check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change.
Bne.s @Changed2 ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait2 ; Loop
Bra.s @1 ;
@Changed2 Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #(ApplePreComp << PreCompOffset)| \ ;
(dr500 << DataRateOffset), \ ;
fdcDRR(A0) ; Set MFM pre-comp.
@MFMLoop Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #ReadMFMID,D0 ; Command.
Bsr WriteToFDC ; Send command.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Write head/drive.
Bne.s @1 ; Error? Then retry.
Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond. <SM4> ws
@Wait3 Bsr GetResult ; Go check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change.
Bne @CheckMFM ; Change? Then check it.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait3 ; Loop until it changes.
@1 Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
If Break Then
_debugger
EndIf
Bsr ResetFDC ; Try resetting FDC.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <LW8>
Move.b #-1,fStatus0(A1) ; Set flag. <LW8>
Moveq #0,D1 ; Init counter. <LW8>
Move.w TimeDBRA,D1 ; DBRA/Millisecond. <LW8>
Asl.l #6,D1 ; DBRA/64 Millisecond. <LW8>
@WaitMFMInt Bsr SenseInterrupt ; Check for interrupt. <LW8>
Cmp.b #-1,fStatus0(A1) ; Done? <LW8>
Bne.s @MFMResetInt ; Change? Then Get out. <LW8>
Subq.l #1,D1 ; Decrement counter. <LW8>
Bne.s @WaitMFMInt ; Loop <LW8>
Move.w #noNybErr,fResult(A1) ; Set flag
@MFMResetInt Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <LW8>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #-1,fStatus0(A1) ; Set flag. <LW8>
Move.b #SetEnableOn,D0 ; Set enable command. <LW8>
Bsr WriteToFDC ; Send it. <LW8>
Move.w fDriveSelect(A1),D0 ; Drive number. <LW8>
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <LW8>
Bsr WriteToFDC ; Enable the drive. <LW8>
Moveq #0,D1 ; Init counter. <LW8>
Move.w TimeDBRA,D1 ; DBRA/Millisecond. <LW8>
Asl.l #8,D1 ; DBRA/256 Millisecond. <LW8>
@WaitMFMEnable Bsr SenseInterrupt ; Go check for interrupt. <LW8>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change. <LW8>
Bne.s @MFMEnable ; Change? Then Get out. <LW8>
Subq.l #1,D1 ; Decrement counter. <LW8>
Bne.s @WaitMFMEnable ; Loop <LW8>
Move.w #noNybErr,fResult(A1) ; Set flag
@MFMEnable Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <LW8>
Clr.b fMotor(A1) ; Clear flag. <LW8>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #$0,D0 ; Standard.
Bsr WriteToFDC ; Send it.
Subq.b #1,fRetries(A1) ; Decrement retry count.
Bpl @MFMRetry ; Retry.
Bra.s @ED ; Try ED.
@CheckMFM Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Tst.w fResult(A1) ; Check error code.
Bne.s @ED ; Error? Then try extended density.
Move.b fSector(A1),D0 ; Sector number read.
Cmp.b fLastSector(A1),D0 ; New sector less than old?
Bls.s @CheckFormat ; Yes? Then determine format.
Move.b D0,fLastSector(A1) ; No? Then save new high sector number.
Bra @MFMLoop ; And do another read.
@CheckFormat Move.b fLastSector(A1),D0 ; High sector number.
Move.w #f720K,fFormat(A1) ; Assume 720K.
Cmp.b #9,D0 ; 9 sectors or less?
Beq @SetQueue ; Yes? Then setup drive queue.
Move.w #f1440K,fFormat(A1) ; No? Then must be 1.4Meg format.
Bra @SetQueue ; Setup drive queue.
@ED Cmp.w #fddTyphoon,fDriveType(A1) ; At least a Typhoon?
Blt @Blank ; No? Then can't check ED.
Move.b #1,fRetries(A1) ; Set retry count.
@EDRetry Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #vertical,D0 ; Perpendicular (1Mbps).
Bsr WriteToFDC ; Send it.
Move.b #(ApplePreComp << PreCompOffset)| \ ;
(dr1000 << DataRateOffset), \ ;
fdcDRR(A0) ; Set pre-comp and data rate.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #ReadMFMID,D0 ; Command.
Bsr WriteToFDC ; Send command.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Write head/drive.
Bne.s @2 ; Error? Then retry.
Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond. <SM4> ws
@Wait4 Bsr GetResult ; Go check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change.
Bne @CheckED ; Change? Then check it.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait4 ; Loop until it changes.
@2 Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
If Break Then
_debugger
EndIf
Bsr ResetFDC ; Try resetting FDC.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <LW8>
Move.b #-1,fStatus0(A1) ; Set flag. <LW8>
Moveq #0,D1 ; Init counter. <LW8>
Move.w TimeDBRA,D1 ; DBRA/Millisecond. <LW8>
Asl.l #6,D1 ; DBRA/64 Millisecond. <LW8>
@WaitEDInt Bsr SenseInterrupt ; Check for interrupt. <LW8>
Cmp.b #-1,fStatus0(A1) ; Done? <LW8>
Bne.s @EDResetInt ; Change? Then Get out. <LW8>
Subq.l #1,D1 ; Decrement counter. <LW8>
Bne.s @WaitEDInt ; Loop <LW8>
Move.w #noNybErr,fResult(A1) ; Set flag
@EDResetInt Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <LW8>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Move.b #-1,fStatus0(A1) ; Set flag. <LW8>
Move.b #SetEnableOn,D0 ; Set enable command. <LW8>
Bsr WriteToFDC ; Send it. <LW8>
Move.w fDriveSelect(A1),D0 ; Drive number. <LW8>
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <LW8>
Bsr WriteToFDC ; Enable the drive. <LW8>
Moveq #0,D1 ; Init counter. <LW8>
Move.w TimeDBRA,D1 ; DBRA/Millisecond. <LW8>
Asl.l #8,D1 ; DBRA/256 Millisecond. <LW8>
@WaitEDEnable Bsr SenseInterrupt ; Go check for interrupt. <LW8>
Cmp.b #-1,fStatus0(A1) ; Wait for status to change. <LW8>
Bne.s @EDEnable ; Change? Then Get out. <LW8>
Subq.l #1,D1 ; Decrement counter. <LW8>
Bne.s @WaitEDEnable ; Loop <LW8>
Move.w #noNybErr,fResult(A1) ; Set flag
@EDEnable Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <LW8>
Clr.b fMotor(A1) ; Clear flag. <LW8>
Tst.w fResult(A1) ; Error?
Bne @ExitSetUp ; Yes? Out of here.
Subq.b #1,fRetries(A1) ; Decrement retry count. <SM19>
Bpl @EDRetry ; Retry. <SM19>
Bra.s @Blank ; <SM19>
@CheckED Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Tst.w fResult(A1) ; Check error code.
Bne.s @Blank ; Error? Must be blank.
Move.w #f2880K,fFormat(A1) ; Assume 2.8.
Move.b #$24,fLastSector(A1); Set number of sectors.
Bra.s @SetQueue ; Yes? Then setup drive queue.
@Blank Move.w #fBlank,fFormat(A1) ; Error? Indicate blank disk.
Clr.w fResult(A1) ;
@SetQueue Move.b fData(A1),fCode(A1) ; Save format code.
Move.b fRetrySeed(A1),fRetries(A1) ; Reset retries.
Lea Blocks,A2 ; Block table.
Move.w fFormat(A1),D1 ; Format code.
Asl.w #1,D1 ; Make index.
Move.w (A2,D1.w),D1 ; Number of blocks.
Move.l fDriveQueue(A1),A2 ; Pointer to drive queue.
Move.w D1,dQDrvSz(A2) ; Install number of blocks.
Move.b #$FF,-1(A2) ; Non single-sided. <LW14>
Cmp.w #f400K,fFormat(A1) ; 400K GCR?
Bne.s @3 ; No? Then double-sided.
Clr.b -1(A2) ; Single-sided.
@3 Btst.b #fWriteStatus,fStatus3(A1) ; Write protected?
Bne @ExitSetup ; No? Then leave.
Move.b #$80,-4(A2) ; Set flag.
Bra @ExitSetUp ; Leave.
@SetMode Tst.b fMotor(A1) ; Motor on?
Bne.s @4 ; Yes? Then set up FDC.
Bsr EnableMotor ; Turn motor on.
Tst.w fResult(A1) ; Get error code.
Bne.s @ExitSetUp ; Error? Out of here.
@4 Move.b #PerpMode,D0 ; Set up perpendicular mode.
Bsr WriteToFDC ; Send it.
Moveq #$0,D0 ; Standard.
Cmp.w #f2880K,fFormat(A1) ; Extended density?
Bne.s @5 ; No? Then horizontal mode.
Moveq #vertical,D0 ; Yes? Set vertical mode.
@5 Bsr WriteToFDC ; Send it.
Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetDriveGCR,D0 ; Set drive mode to GCR.
Moveq #(dr500 << DataRateOffset),D1 ; Data rate.
Cmp.w #fUnknownGCR,fFormat(A1) ; GCR format?
Ble.s @6 ; Yes? Then set it.
Move.b #SetDriveMFM,D0 ; Set drive to MFM.
Moveq #(dr500 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Date rate/pre-comp for HD.
Cmp.w #f1440K,fFormat(A1) ; Double density?
Ble.s @6 ; Yes? Then set it.
Moveq #(dr1000 << DataRateOffset) | \ ;
(ApplePreComp << PreCompOffset), \ ;
D1 ; Must be extended density.
@6 Move.b D1,fdcDRR(A0) ; Set data rate/pre-comp.
Bsr WriteToFDC ; Send mode byte.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send it.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Waitx Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Done?
Bne.s @ExitSetUp ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Waitx ; Loop
Move.w #noNybErr,fResult(A1) ; Set flag
If Break Then
_debugger
EndIf
@ExitSetUp Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.l (Sp)+,A2 ; Restore A2.
Rts ; And leave.
Blocks Dc.w 0,0,800,1600,1600,0,1440,2880,5760
;------------------------------------------------------------------------------
; Routine: CheckError
; Inputs: A1 -> Drive record.
; Outputs: D1 -> 0 - OK, ~0 - Error.
; Function: Look at status returned by FDC for error message.
; Called By: Prime, Verify.
;------------------------------------------------------------------------------
CheckError Move.b fStatus0(A1),D0 ; Status 0.
Move.w #tk0BadErr,D1 ; Assume drive error.
Btst #fFDDErr,D0 ; Equipment check?
Bne.s ExitError ; Yes? The leave.
Move.w #offLinErr,D1 ; Assume disk is ejected.
Btst #fReady,D0 ; Not ready?
Bne.s ExitError ; Yes? The leave.
Move.b fStatus2(A1),D0 ; Status 2.
Move.w #noDtaMkErr,D1 ; Assume deleted data mark.
Btst #fCntrlMrk,D0 ; Deleted data mark?
Bne.s ExitError ; Yes? Then leave.
Move.w #badDCksum,D1 ; Assume data checksum error.
Btst #fDataField,D0 ; Data checksum error?
Bne.s ExitError ; Yes? Then leave.
Move.w #seekErr,D1 ; Assume wrong cylinder.
Btst #fNoCylndr,D0 ; Wrong cylinder error?
Bne.s ExitError ; Yes? Then leave.
Move.w #seekErr,D1 ; Assume no data mark.
Btst #fBadCylndr,D0 ; Bad track?
Bne.s ExitError ; Yes? Then leave.
Move.w #noDtaMkErr,D1 ; Assume no data mark.
Btst #fNoDataAddrMrk,D0 ; No data mark error?
Bne.s ExitError ; Yes? Then leave.
Move.b fStatus1(A1),D0 ; Status 1.
Move.w #badCksmErr,D1 ; Assume address checksum error.
Btst #fDataErr,D0 ; Address checksum error?
Bne.s ExitError ; Yes? Then leave.
Move.w #wrUnderrun,D1 ; Assume underrun/overrun error.
Btst #fOvrRun,D0 ; Underrun/overrun error?
Bne.s ExitError ; Yes? Then leave.
Move.w #sectNFErr,D1 ; Assume sector not found.
Btst #fNoData,D0 ; Sector not found error?
Bne.s ExitError ; Yes? Then leave.
Move.w #wPrErr,D1 ; Assume write protected.
Btst #fWrtPrtct,D0 ; Write protected?
Bne.s ExitError ; Yes? Then leave.
Move.w #noAdrMkErr,D1 ; Assume no address mark.
Btst #fNoAddrMrk,D0 ; No address mark?
Bne.s ExitError ; Yes? Then leave.
Move.w #noErr,D1 ; Set no error.
ExitError Move.w D1,fResult(A1) ; Save result.
Rts ; Leave.
;------------------------------------------------------------------------------
; Routine: SeekToTrack
; Inputs: A0 -> FDC address.
; A1 -> Drive record.
; D2 -> Cylinder number.
; Outputs: D0 -> 0 - OK, ~0 - Error.
; Function: Seek to a given cylinder.
; Called By: Prime, Format, Verify.
;------------------------------------------------------------------------------
SeekToTrack Tst.b fMotor(A1) ; Drive turned on?
Bne.s @DoSeek ; Yes? Then do seek.
Bsr EnableMotor ; Turn motor on.
Tst.w fResult(A1) ; Error?
Bne.s @Exit ; Yes? Out of here.
@DoSeek Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #Seek,D0 ; Seek command.
Bsr WriteToFDC ; Send byte.
Move.b fDriveSelect(A1),D0 ; Drive select.
Bsr WriteToFDC ; Send byte.
Move.b D2,D0 ; Cylinder number.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send byte.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Wait Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Change yet?
Bne.s @SecondWait ; Yes? Go Check second conditon.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
If Break Then
_debugger
EndIf
@SecondWait Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
Move.b fdcMSR(A0),D0 ; Status?
And.b #(1 << fDrv0Bsy)| \ ;
(1 << fDrv1Bsy), \ ;
D0 ; Still seeking?
Beq.s @Exit ; Yes? Then loop.
Subq.l #1,D1 ; Decrement counter.
Bne.s @SecondWait ; Loop
If Break Then
_debugger
EndIf
Move.w #cantStepErr,fResult(A1) ;
@Exit Rts ; And leave.
;------------------------------------------------------------------------------
; Routine: Track0
; Inputs: A0 -> FDC address.
; A1 -> Drive record.
; Outputs: D0 -> 0 - OK, ~0 - Error.
; Function: Recalibrate to cylinder 0.
; Called By: SetUpFDC.
;------------------------------------------------------------------------------
Track0 Tst.b fMotor(A1) ; Drive turned on?
Bne.s @DoRecalibrate ; Yes? Then do recalibrate.
Bsr EnableMotor ; Turn motor on.
Tst.w fResult(A1) ; Error?
Bne.s @Exit ; Yes? Out of here.
@DoRecalibrate Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #Recalibrate,D0 ; Recalibrate command.
Bsr WriteToFDC ; Send byte.
Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send byte.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Wait Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Done?
Bne.s @Done ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
Move.b #1,D0 ; Report error.
If Break Then
_debugger
EndIf
@Done Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
@Exit Rts ; And leave.
;------------------------------------------------------------------------------
; Routine: EnableMotor
; Inputs: A0 -> FDC address.
; A1 -> Drive record.
; Outputs: None.
; Function: Turn motor on to drive.
; Called By: SetUpFDC, SeekToTrack, Track0.
;------------------------------------------------------------------------------
EnableMotor Move.b #-1,fStatus0(A1) ; Set flag.
Move.b #SetMotorOn,D0 ; Motor on command.
Bsr WriteToFDC ; Send command.
@0 Move.b fDriveSelect(A1),D0 ; Drive select.
Move.b #DisableFDCInt,VIA2IER ; Disable interrupts. <SM23>
Bsr WriteToFDC ; Send drive ID.
Move.b #1,fMotor(A1) ; Set flag.
Moveq #0,D1 ; Init counter. <SM9>
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@Wait Bsr SenseInterrupt ; Check for interrupt. <SM23>
Cmp.b #-1,fStatus0(A1) ; Done?
Bne.s @Done ; Change? Then Get out.
Subq.l #1,D1 ; Decrement counter.
Bne.s @Wait ; Loop
If Break Then
_debugger
EndIf
@Done Move.b #EnableFDCInt,VIA2IER ; Enable interrupts. <SM23>
@Exit Rts ; And leave.
;------------------------------------------------------------------------------
; Routine: WriteToFDC
; Inputs: A0 -> FDC address.
; D0 -> Byte to write.
; Outputs: D1 -> 0 - OK, ~0 - Error.
; Function: Write byte to FDC.
;------------------------------------------------------------------------------
WriteToFDC Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
Asl.l #1,D1 ; DBRA/512 Millisecond. <LW15>
Swap D0 ; Data in high byte.
@WriteLoop Move.b fdcMSR(A0),D0 ; Main status.
Bpl.s @1 ; Not ready? Loop.
Btst #fDIO,D0 ; Correct direction?
Bne.s @1 ; No? Then loop.
Swap D0 ; Data in low word.
Move.b D0,fdcDATA(A0) ; Write byte.
@WaitLoop Tst.b fdcMSR(A0) ; Status.
Bpl.s @0 ; Wait for FDC to take it.
Moveq #0,D1 ; Set noErr.
@ExitWrite Rts ; And return. <SM6>
@0 Subq.l #1,D1 ; Decrement counter.
Bne.s @WaitLoop ;
Bra.s @2 ;
@1 Subq.l #1,D1 ; Decrement counter.
Bne.s @WriteLoop ; Loop.
@2 Moveq #1,D1 ; Set flag.
If Break Then
_debugger
EndIf
Bra.s @ExitWrite ; And leave. <SM6>
;------------------------------------------------------------------------------
; Routine: ReadFromFDC
; Inputs: A0 -> FDC address.
; Outputs: D0 -> Byte read.
; D1 -> 0 - OK, ~0 - Error.
; Function: Read byte from FDC.
;------------------------------------------------------------------------------
ReadFromFDC Moveq #0,D0 ; Init counter.
Move.w TimeDBRA,D0 ; DBRA/Millisecond.
Asl.l #8,D0 ; DBRA/256 Millisecond.
Asl.l #1,D0 ; DBRA/512 Millisecond. <LW15>
@ReadLoop Move.b fdcMSR(A0),D1 ; Main status.
Bpl.s @0 ; Not ready? Check timeout.
Btst #fCmdBsy,D1 ; Command still busy?
Beq.s @1 ; No? Then bail out.
Btst #fDIO,D1 ; Correct direction?
Beq.s @0 ; No? Check timeout.
Move.b fdcDATA(A0),D0 ; Yes? Read byte.
Moveq #0,D1 ; Set noErr.
@ExitRead Rts ; And return. <SM6>
@0 Subq.l #1,D0 ; Decrement counter.
Bne.s @ReadLoop ; Loop.
@1 Moveq #1,D1 ; Set flag.
If Break Then
_debugger
EndIf
Bra.s @ExitRead ; And leave. <SM6>
;------------------------------------------------------------------------------
; Routine: FDCDMAInt
; Inputs: None.
; Outputs: None.
; Function: FDC DMA Interrupt handler.
; Since the floppy does not use the DMA interrupt this is here to
; handle the case of a DMA bus error. Added in <LW12>
;------------------------------------------------------------------------------
FDCDMAInt Move.l A0,-(Sp) ; Save registers.
Movea.l #pscControl32,A0 ; PSC control register.
Move.w #(1 << pscSWReset) | \ ;
(1 << pscSense), \ ;
(A0) ; Reset channel.
; Compile out debug string <LW28>
If Break Then
pea @BusErrStr ;
_DebugStr ; Call Macsbug.
EndIf
@ExitFDCDMA Move.l (Sp)+,A0 ; Restore registers.
Rts
; Compile out string <LW28>
If Break Then
@BusErrStr dc.b 'A DMA bus error have occur'
EndIf
;------------------------------------------------------------------------------
; Routine: Handler
; Inputs: None.
; Outputs: None.
; Function: FDC Interrupt handler.
;------------------------------------------------------------------------------
HandlerRegs REG A0-A2/D0-D2
Handler Movem.l HandlerRegs,-(Sp) ; Save registers.
Btst.b #FDCInt,VIA2IFR ; FDC causing interrupt? <SM1> RLM
Beq.s @ExitHandler ; No? Leave.
Movea.l NewAgeVars,A1 ; Pointer to DCE.
Movea.l dCtlStorage(A1),A1 ; Floppy info records.
Movea.l #NewAge32,A0 ; Base address of NewAge.
Move.b #SenseIntStatus,D0 ; Sense interrupt status command.
Bsr WriteToFDC ; Send command.
Bsr ReadFromFDC ; Get Status0.
Move.b D0,D2 ; Save it.
And.w #(1 << fDrive),D0 ; Drive number.
Move.l A1,D1 ; Does drive record exist?
Beq.s @ExitHandler ; No? Then leave.
Cmp.w fDriveSelect(A1),D0 ; Are we looking at the right record?
Beq.s @Check ; Yes? Then get rest of status.
Move.l fNextRecord(A1),D1 ; Does drive record exist?
Beq.s @ExitHandler ; No? Then leave.
Move.l D1,A1 ; Pointer to next drive record.
@Check Move.b D2,fStatus0(A1) ; Save status 0.
Move.b D2,D0 ; Status 0.
Lsr.b #IntStatOffset,D0 ; Int code in bottom 2 bits.
Beq.s @CheckComplete ; Normal? Then check for a completion.
Cmp.b #AbnrmlTrmnt,D0 ; Abnormal?
Beq.s @CheckComplete ; Then check for a completion.
Cmp.b #CssttChng,D0 ; Cassette change?
Beq.s @Cassette ; Yes? Then check for insert or eject.
Bsr ResetFDC ; Illegal command? Reset FDC.
Clr.b fMotor(A1) ; Clear flag. <SM4> ws
Bra.s @ExitHandler ; And leave.
@Cassette Move.w #fNone,fFormat(A1) ; Assume disk is being ejected.
Btst #fDiskStatus,D2 ; Floppy in?
Bne.s @ExitHandler ; No? Then leave.
Tst.b DTInstalled(A1) ;
Bne.s @ExitHandler ;
Lea DTQE(A1), A0 ; A0->deferred task queue element.
Lea DeferPost,A2 ; Get DT address.
Move.l A2, dtAddr(A0) ; Set address of DT.
Move.l A1, dtParm(A0) ; Set variable pointer to Newage vars.
Addq.b #1,DTInstalled(A1) ;
MoveA.l JDTInstall, A1 ;
Jsr (A1) ; install deferred task
@ExitHandler Movem.l (Sp)+,HandlerRegs ; Restore registers.
Rts
@CheckComplete Move.l fCompletion(A1),D0 ; Completion routine.
Beq.s @ExitHandler ; None? Then leave.
Clr.l fCompletion(A1) ; Clear pointer.
Move.l D0,A2 ; Pointer to routine.
Jsr (A2) ; Call it.
Bra.s @ExitHandler ; And leave.
DeferPost Movem.l D0/A0, -(SP) ;
Move.w fDriveNum(A1),D0 ; Drive number.
Move.l fDriveQueue(A1),A0 ; Drive queue.
Move.b #1,-3(A0) ; Set disk in flag.
Move.w #mUnknown,fMediaType(A1)
Ext.l D0 ; Drive number.
Lea diskInsertEvt,A0 ; Event number.
_PostEvent ; Post it.
Clr.b DTInstalled(A1) ;
Movem.l (Sp)+,D0/A0 ; Restore registers.
Rts
; Added SenseInterrupt because when Newage interrupts After a command, it does not always have
; the Command Busy bit clear, as it should. This routine will wait until the bit is cleared
; before doing anything else. <SM23>
;------------------------------------------------------------------------------
; Routine: SenseInterrupt
; Inputs: None.
; Outputs: None.
; Function: FDC Interrupt handler.
;------------------------------------------------------------------------------
SenseRegs REG A0-A2/D0-D3
SenseInterrupt Movem.l SenseRegs,-(Sp) ; Save registers.
@CheckFDC Btst.b #FDCInt,VIA2IFR ; FDC causing interrupt?
Beq.s @ExitSense ; No? Leave.
Movea.l NewAgeVars,A1 ; Pointer to DCE.
Movea.l dCtlStorage(A1),A1 ; Floppy info records.
Movea.l #NewAge32,A0 ; Base address of NewAge.
@Ack Move.b fdcMSR(A0),D0 ; Main status register.
Btst #fCmdBsy,D0 ; Busy bit set yet?
Bne.s @Ack ; No? then wait until it is!
@SenseInt Move.b #SenseIntStatus,D0 ; Sense interrupt status command.
Bsr WriteToFDC ; Send command.
Bsr ReadFromFDC ; Get Status0.
Move.b D0,D2 ; Save it.
Btst #fSeek,D2 ; Was it a seek of recal command?
Beq.s @nocylinder ; Only one result byte if it is not.
Bsr ReadFromFDC ; Get PCN (present cylinder number).
Move.b D0,D1 ; Save PCN.
@nocylinder Move.b D2,D0 ; Status 0.
And.w #(1 << fDrive),D0 ; Drive number.
Move.l A1,D3 ; Does drive record exist?
Beq.s @ExitSense ; No? Then leave.
Cmp.w fDriveSelect(A1),D0 ; Are we looking at the right record?
Beq.s @Check ; Yes? Then get rest of status.
Move.l fNextRecord(A1),D3 ; Does drive record exist?
Beq.s @ExitSense ; No? Then leave.
Move.l D3,A1 ; Pointer to next drive record.
@Check Move.b D2,fStatus0(A1) ; Save status 0.
Btst #fSeek,D2 ; Was it a seek of recal command?
Beq.s @ChkErr ; Only one result byte if it is not.
Move.b D1,fCylinder(A1) ; Save cylinder number.
@ChkErr
; Move.w #tk0BadErr,D0 ; Assume drive error.
; Btst #fFDDErr,D2 ; Equipment check?
; Bne.s @TestTrmnt ; Yes? The leave.
Move.w #offLinErr,D0 ; Assume disk is ejected.
Btst #fReady,D2 ; Not ready?
Bne.s @TestTrmnt ; Yes? The leave.
Clr.w D0 ; Set no error.
@TestTrmnt Move.w D0,fResult(A1) ; Save result.
Move.b D2,D0 ; Status 0.
Lsr.b #IntStatOffset,D0 ; Int code in bottom 2 bits.
Beq.s @CheckComplete ; Normal? Then check for a completion.
Cmp.b #AbnrmlTrmnt,D0 ; Abnormal?
Beq.s @CheckComplete ; Then check for a completion.
@ExitSense Movem.l (Sp)+,SenseRegs ; Restore registers.
Rts
@CheckComplete Move.l fCompletion(A1),D0 ; Completion routine.
Beq.s @ExitSense ; None? Then leave.
Clr.l fCompletion(A1) ; Clear pointer.
Move.l D0,A2 ; Pointer to routine.
Jsr (A2) ; Call it.
Bra.s @ExitSense ; And leave.
;------------------------------------------------------------------------------
; Routine: GetResult
; Inputs: None.
; Outputs: None.
; Function: FDC Interrupt handler.
;------------------------------------------------------------------------------
ResultRegs REG A0-A2/D0-D3
GetResult Movem.l ResultRegs,-(Sp) ; Save registers.
@CheckFDC Btst.b #FDCInt,VIA2IFR ; FDC causing interrupt?
Beq @ExitResult ; No? Leave.
Movea.l NewAgeVars,A1 ; Pointer to DCE.
Movea.l dCtlStorage(A1),A1 ; Floppy info records.
Movea.l #NewAge32,A0 ; Base address of NewAge.
@Ack Move.b fdcMSR(A0),D0 ; Main status register.
Btst #fCmdBsy,D0 ; Busy bit Reset yet?
Beq.s @Ack ; No? then wait until it is!
Bsr ReadFromFDC ; Get status register 0.
Move.b D0,D1 ; Copy status.
And.w #1,D1 ; Drive number.
Move.l A1,D3 ; Does drive record exist?
Beq.s @ExitResult ; No? Then leave.
Cmp.w fDriveSelect(A1),D1 ; Are we looking at the right record?
Beq.s @0 ; Yes? Then get rest of status.
Move.l fNextRecord(A1),D3 ; Does drive record exist?
Beq.s @ExitResult ; No? Then leave.
Move.l D3,A1 ; Pointer to next drive record.
@0 Move.b D0,fStatus0(A1) ; Save it.
Move.b fdcMSR(A0),D0 ; Check for end of result.
Btst #fCmdBsy,D0 ; Done?
Beq.s @ExitResult ; Yes? Then leave.
Bsr ReadFromFDC ; Get status register 1.
Move.b D0,fStatus1(A1) ; Save it.
Bsr ReadFromFDC ; Get status register 2.
Move.b D0,fStatus2(A1) ; Save it.
Bsr ReadFromFDC ; Get cylinder number.
Move.b D0,fCylinder(A1) ; Save it.
Bsr ReadFromFDC ; Get head number.
Move.b D0,fHead(A1) ; Save it.
Bsr ReadFromFDC ; Get sector number.
Move.b D0,fSector(A1) ; Save it.
Bsr ReadFromFDC ; Get format code.
Move.b D0,fData(A1) ; Save it.
Moveq #0,D1 ; Init counter.
Move.w TimeDBRA,D1 ; DBRA/Millisecond.
Asl.l #8,D1 ; DBRA/256 Millisecond.
@1 Move.b fdcMSR(A0),D0 ; Main status.
Btst #fCmdBsy,D0 ; Still busy?
Beq.s @2 ; No? Then leave.
Subq.l #1,D1 ; Decrement counter.
Bne.s @1 ; Loop till timeout.
; Compile out debugger <LW28>
If Break Then
_Debugger ; Die for now.
EndIf
@2 Bsr CheckError ; Check I/O result.
@CheckComplete Move.l fCompletion(A1),D0 ; Completion routine.
Beq.s @ExitResult ; None? Then leave.
Clr.l fCompletion(A1) ; Clear pointer.
Move.l D0,A2 ; Pointer to routine.
Jsr (A2) ; Call it.
@ExitResult Movem.l (Sp)+,ResultRegs ; Restore registers.
Rts
;------------------------------------------------------------------------------
; Routine: Initialize FDC
; Inputs: A0 -> FDC address.
; Outputs: None.
; Function: Reset FDC during open or after serious error.
; Called by: Open, Handler.
;------------------------------------------------------------------------------
ResetFDC Move.b #(1 << fReset) | \ ;
(NoPreComp << PreCompOffset) | \ ;
(dr500 << DataRateOffset), \ ;
fdcDRR(A0) ; Reset the FDC.
Move.b #SelectDriveType,D0 ; Select drive type command.
Bsr WriteToFDC ; Send command.
Move.b #drvApple,D0 ; Apple drive type.
Bsr WriteToFDC ; Select it.
Move.b #Configure,D0 ; Configure command.
Bsr WriteToFDC ; Send byte to FDC.
Clr.b D0 ; ???
Bsr WriteToFDC ; Send byte to FDC.
Move.b #$F,D0 ; Set FIFO to 0 bytes. <SM9>
Bsr WriteToFDC ; Send byte to FDC.
Move.b #$0,D0 ; Start precomp at this track.
Bsr WriteToFDC ; Send byte to FDC.
Move.b #Specify,D0 ; Specify command.
Bsr WriteToFDC ; Send byte to FDC.
Moveq #0,D0 ; Step rate/head unload.
Bsr WriteToFDC ; Send byte to FDC.
Moveq #0,D0 ; Head load/DMA.
Bsr WriteToFDC ; Send byte to FDC.
Rts ; Return.
;------------------------------------------------------------------------------
; Data: Icon data and “where” string.
;------------------------------------------------------------------------------
STRING PASCAL
FrigidaireInternal
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000010000111111111111100100000
Dc.l %00000011000100000000000100100000
Dc.l %00111111100100111111100100100000
Dc.l %00000011000100000000000100100000
Dc.l %00000010000111111111111100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000111111111111100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000001100000000000110110000
Dc.l %00000000001100000000000100110000
Dc.l %00000000001100000110000110110000
Dc.l %00000000001100000110000100110000
Dc.l %00000000001100000000000110110000
Dc.l %00000000001100000000000100110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111100000000111110000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000110000111111111111111100000
Dc.l %00000111000111111111111111100000
Dc.l %01111111100111111111111111100000
Dc.l %01111111110111111111111111100000
Dc.l %01111111100111111111111111100000
Dc.l %00000111000111111111111111100000
Dc.l %00000110000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111100000000111110000
Dc.l %00000000000000000000000000000000
Dc.l 'Internal'
FrigidaireExternal
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000010000111111111111100100000
Dc.l %00000011000100000000000100100000
Dc.l %00111111100100111111100100100000
Dc.l %00000011000100000000000100100000
Dc.l %00000010000111111111111100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000111111111111100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000000100000000000100100000
Dc.l %00000000001100000000000110110000
Dc.l %00000000001100000000000100110000
Dc.l %00000000001100000110000110110000
Dc.l %00000000001100000110000100110000
Dc.l %00000000001100000000000110110000
Dc.l %00000000001100000000000100110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111100000000111110000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000110000111111111111111100000
Dc.l %00000111000111111111111111100000
Dc.l %01111111100111111111111111100000
Dc.l %01111111110111111111111111100000
Dc.l %01111111100111111111111111100000
Dc.l %00000111000111111111111111100000
Dc.l %00000110000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000000111111111111111100000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111111111111111110000
Dc.l %00000000001111100000000111110000
Dc.l %00000000000000000000000000000000
Dc.l 'External'
QFCInternal
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000111110000
Dc.l %00000000000000000000000011100000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %01111111111111111111111111111110
Dc.l %01000000001000000000100000000010
Dc.l %01011000001000000000101111111010
Dc.l %01011000001000000000100000000010
Dc.l %01000000001000000000100000000010
Dc.l %01001000001000000000100000011010
Dc.l %01111111111111111111111111100110
Dc.l %00111111111111111111111111111100
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l 'Internal'
QFCExternal
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000111110000
Dc.l %00000000000000000000000011100000
Dc.l %00000000000000000000000001000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %01111111111111111111111111111110
Dc.l %01000000001000000000100000000010
Dc.l %01011000001000000000101111111010
Dc.l %01011000001000000000100000000010
Dc.l %01000000001000000000100000000010
Dc.l %01001000001000000000100000011010
Dc.l %01111111111111111111111111100110
Dc.l %00111111111111111111111111111100
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %00000000000000000000000000000000
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111110
Dc.l 'External'
MediaIcon Dc.l %01111111111111111111111111111000
Dc.l %10000001000000000000000100000100
Dc.l %10000001000000000111000100000010
Dc.l %10000001000000001000100100000001
Dc.l %10000001000000001000100100000001
Dc.l %10000001000000001000100100000001
Dc.l %10000001000000001000100100000001
Dc.l %10000001000000001000100100000001
Dc.l %10000001000000000111000100000001
Dc.l %10000001000000000000000100000001
Dc.l %10000000111111111111111000000001
Dc.l %10000000000000000000000000000001
Dc.l %10000000000000000000000000000001
Dc.l %10000000000000000000000000000001
Dc.l %10000000000000000000000000000001
Dc.l %10000000000000000000000000000001
Dc.l %10000000000000000000000000000001
Dc.l %10000000000000000000000000000001
Dc.l %10000111111111111111111111100001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %10001000000000000000000000010001
Dc.l %01111111111111111111111111111110
Dc.l %01111111111111111111111111111000
Dc.l %11111111111111111111111111111100
Dc.l %11111111111111111111111111111110
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %11111111111111111111111111111111
Dc.l %01111111111111111111111111111110
Dc.l 'Internal'
END