; ; File: SonyRWT.a ; ; Contains: Sony 3.5" Floppy Disk Driver Read/Write Track Logic ; ; Written by: Larry Kenyon 05-May-83 ; ; Copyright: © 1983-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 12/13/93 PN Roll in KAOs and Horror changes to support Malcom and AJ ; machines ; 1/10/93 RC Added Nop for Smurf ; 12/14/92 RC Restore Pre-PDM D2 with Horror Roll-in ; 12/7/92 rab Roll in Horror changes. Comments followÉ ;

2/13/92 CMP Patched AdrDtaErr to check if retries are disabled before ; attempting them. ;

10/18/91 CMP Overpatch for SWIM2 support. Also, changed the way the drives are ; disabled since those signals are no longer gated by MotorOn. ; 12/02/92 HY Put back hasPwrControls conditional (for LC930, non-universal) ; and fix a branch out of range. ; <5> 7/14/92 CSS Fixed the comment below so an exact version of this ; file could be copied into SuperMario. ; <4> 4/27/92 JSM Get rid of conditionals: supportsPWM, supportsDCD, and ; hasHarpoVIA are always false, forROM, supportsMFM, forDiskDup, ; isUniversal, hasPowerMgr, and hasPwrControls are always true ; (although hasPowerMgr currently isnÕt for the ROM, it will be ; and was always ORed with hasPwrControls here anyway). This file ; now has no conditionals. ; <3> 1/21/91 SWC Cleaned up header comments. ; <2> 5/11/90 MSH Converted all onHcMac or hasPowerMgr conditionals to universal ; versions. Test is based on the existence of the power manager ; bit in the config word. ; <2.4> 5/23/89 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <2.3> 4/29/89 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <2.2> 4/10/89 gmr No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <2.1> 2/21/89 GGD Fixed bugs in GotSect, was using (a1,d6), but d6 may be invalid, ; use (a1,d1) instead, since GetDrv1 has been called. Let new ; interface drives (800K/SuperDrive) attempt 1 to 1 writes, since ; it will always work in MFM, and should usually work in GCR. ; Changed bit number of SCC/VIA direction bit save in chipState. ; <2.0> 12/15/88 GGD Changed some machine based conditionals to feature based. ; <1.1> 11/11/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <1.9> 9/29/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.8> 9/19/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.8> 8/19/88 SWC Save the format byte returned by RdAddr if for disk duplicator. ; <1.7> 8/16/88 GGD Restored VIA Buf B Direction bit in EmptyPD for HcMac ; <1.7> 8/9/88 GGD Restored VIA Buf B Direction bit in EmptyPD for HcMac ; <1.6> 7/15/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.5> 6/15/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.4> 5/25/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.3> 5/23/88 GGD No changes, entire sony driver checked out and in as a group. ; <1.2> 5/3/88 GGD No changes, entire sony driver checked out and in as a group. ; <1.1> 4/18/88 GGD Merged in MFM support by Steve Christensen ; 3/28/88 SWC GotSect: made 1-sector-wait on writes for GCR disks only (MFM ; does 1-1). ; 2/22/88 SWC OnTrack1: restored drive vars offset to D6 after RdData trashes ; it. ; <1.0> 2/12/88 BBM Adding file for the first time into EASEÉ ; 2/4/88 SWC DiskPrime: moved the SetChipMode and DiskSelect calls to before ; the branch to the DCD code (this was duplicated but now removed ; from SonyDCD). ; 10/13/87 MSH Port to HcMac (Laguna). ; 10/8/87 SWC Decrement the sector number for MFM disks when calculating cache ; offsets since MFM disks start with sector 1. ; 9/30/87 SWC Don't call SetChipMode if an IWM is installed and SetIWMMode ; wouldn't have been called anyway. ; 12/4/86 SWC Check disk format on entry if the disk is unclamped. Patched ; GetTrack to jump to mGetTrack (SonyMFM.a) if we're running in ; MFM mode (different sector layout). Set sector time to 7.5ms for ; MFM disks in OnTrack since the track format has fixed sector ; spacing. ; 8/22/86 TJ Made 400K Sony drive support conditional under 'supportsPWM'; ; not supported on nuMac. ; 8/5/86 TJ Disabled some cache code so that writes update the disk, and ; hence the tags. (Tags were not in sync w/ sector data.) ; 5/5/86 RDC Changed old onMidmac conditional to onNuMac ; 11/3/85 LAK Fixed bug in last fix (track cacheing was always turned off). ; 10/31/85 LAK Turn off cache if RDData hook has been replaced (attempt to get ; other copy-protection schemes to work). ; 10/29/85 LAK Turn off cache on read errors (attempt to get Jazz copy ; protection to work reasonably). ; 10/25/85 LAK Skip thermal drift adjust for new drive (still check it). Use ; NewIntf rather than Sides to determine whether drive has new ; interface. Increment DriveErrs for address and data errors. On ; RWT waits, set up timer first before calling EmptyPD for more ; accurate waits (use TimeSetUp and TimeGo). ; 10/24/85 LAK Added support for track caching. Open up all ints after r/w of a ; sector to see if this fixes keyboard. ; 10/22/85 LAK Use CurSector to store sector number we are reading/writing ; instead of using TagData low-memory var which is overwritten on ; reads. For writes, don't allow retries before reseek for bad ; addrmark errors (should reduce the likelihood off-track ; trashing). ; 9/2/85 LAK Give an early warning for two-sided diskettes in old drives (new ; file system doesn't catch it as quickly). ; 8/14/85 LAK Don't overwrite TagData+10 with Time on writes. ; 7/29/85 RDC Added changes for MidMac: - changed interrupt level settings to ; use equates - removed DCD code - skip track speed checking ; 1/15/85 JTC Converted to MDS ; 11/10/84 LAK Cut enable to drive if no DIP at prime: try to prevent drive ; tick. ; 11/2/84 LAK Sped up logical block mapping. ; 10/26/84 LAK Patched Got1Sect to make 2-1 write possible; interrupts are ; always enabled now after every sector and 1-1 writes are always ; prevented. ; 8/20/83 LAK Added support of SpdAdjErr, SeekErr, SectNFErr (D0 did not ; necessarily have an error code in these cases). ; 8/20/83 LAK Added test of DskWr11 boolean before giving up on 1-1 writing. ; 8/15/83 LAK Verify mode bit is bit 6 now; added Andy's optimizations. ; 8/11/83 LAK Removed statistics; added support for 2-sided drives. ; 8/6/83 LAK Added support for read/verify mode. Increments RndSeed when ; wrong sector passes by . . . ; 7/24/83 LAK Fixed bug in EmptyPD (serial driver trashes A1 . . .) by ; reverting to ROM 3.1 code. ; 7/21/83 LAK If TagBufStrt drive variable is non-zero, tag data is now ; stripped from the data stream and read/written to/from the ; separate buffer. ; 7/10/83 LAK Fixed bug in thermal-drift compensation code. ; 6/23/83 LAK Updated to compensate for speed thermal drift! Subroutined the ; 'drive exist' and 'disk-in-place' checks to share with the disk ; VBL task. ; 5/27/83 LAK Changed for new 5-speed class format ; 5/11/83 LAK MakeSpdTbl no longer trashes A1 on error path (in DoRecal). ; 5/5/83 LAK Adapted from twiggy driver for 3-1/2 inch drive . . . ; title 'File: SonyRWT.a' ;_______________________________________________________________________ ; ; This is the mainline of the disk driver. It processes ; the request parameter block a track at a time. ; ; Arguments: A0 (input) -- pointer to request parameter block ; A1 (input) -- pointer to disk DCE ;_______________________________________________________________________ ; Here is the prime routine, which gets reads and writes going. BLANKS ON STRING ASIS DiskPrime MOVE.L JDiskPrime,-(SP) RTS jtDiskPrime ORI #VIAIntMask,SR ; exclude VBL interrupts <29Jul85> MOVE.W IOTrap(A0),D3 ; save I/O command BTST #6,IOPosMode+1(A0) ; check for read verify mode SNE DskVerify ; note for later BSR.S CkDrvNum ; check for valid drive number and setup BNE DiskErr ; exit if bad drive error MOVE.W D3,Command(A1) ; note I/O command ; ok, we should already know what's connected out there . . . ; if nothing, then just exit. . . otherwise, select the drive ; and continue . . . MOVEQ #NoDriveErr,D0 ; assume no drive installed <03Mar85> TST.B Installed(A1,D1) ; 1=installed, $FF=not <03Mar85> BMI DiskErr ; exit if nothing connected <03Mar85> IF hasPwrControls THEN ; TestFor hwCbPwrMgr BEQ.S @pmgrdone BSR TurnIWMon ; Turn IWM on with pmgr call @pmgrdone ENDIF ; TST.B isSWIM(A1) ;Is a SWIM installed? BPL.S @00 ;-> no, skip BSR SetChipMode ;Make sure the chip is set up OK @00 ; BSR DiskSelect ; select the appropriate interface ; check disk-in-place at the drive . . . (may have been manually ejected) MOVEQ #DIPAdr,D0 ; BSR AdrAndSense ; sets up A0,A1,A2,D1 BPL.S @1 ; br if disk in place CLR.B DiskInPlace(A1,D1) ; no diskette here MOVE.B #$86,wZeroes(A0) ;Cut drive enable (SWIM2 style) <2> if NonSerializedIO then nop ; force write to complete endif TST.B MtrOff(A0) ; cut enable to drive to prevent ticking MOVEQ #OffLinErr,D0 ; report it as no DIP . . . BRA DiskErr ; @1 CMP.B #2,DiskInPlace(A1,D1) ; is it already clamped? BEQ.S CkWrProt ; br if so CLR.B mfmDisk(A1,D1) ;Make sure we're in GCR mode on ; powerup for proper disk chucking TST.B isSWIM(A1) ;Is a SWIM installed? BPL.S @10 ;-> no, skip BSR SetChipMode ;switch the SWIM chip to IWM mode @10 ; BSR FastPower ; power-on drive (no wait cause we'll BSR Recal ; call MakeSpdTbl) and recal BMI.S DskImmOff ; exit on errors BSR MakeSpdTbl ; figure speeds out via tach BNE.S DskImmOff ; exit on errors MOVEQ #WrProtAdr,D0 ; once we recal it should be safe BSR AdrAndSense ; to check write protect . . . SPL WriteProt(A1,D1) ; write-protect sense (FF=writeprot) CLR.B TwoSideFmt(A1,D1) ; assume one-sided disk format at first MOVE.B #2,DiskInPlace(A1,D1) ; note that we have recal'ed BRA ChkDiskType ;Find out how the disk's formatted ; check for write-protected diskette and a write CkWrProt BSR CheckRead ; is it a read? BEQ.S RWPower ; br if so MOVE.W TagData+8,FirstFSeq(A1) ; save the first file sequence number TST.B WriteProt(A1,D1) ; FF=writeprotected BPL.S RWPower ; branch if not MOVEQ #WPrErr,D0 ; diskette write-protected! DskRWOff MOVE.W PwrOffTime(A1),D2 ; read/write power-down time BRA.S POffExit ; speed determine errors DskImmOff MOVEQ #0,D2 ; immediate power-down for recal and ; The following exit is shared by the Format/Verify control routines POffExit MOVE.W D0,-(SP) ; save error code MOVE.W D2,D0 ; power-down time BSR PowerDown ; initiate powerdown MOVE.W (SP)+,D0 ; restore error code ; here we handle the disk priming errors DiskErr ANDI #$F8FF,SR ; open up interrupts BRA DiskDone ; tell the OS about it ; make sure the drive is powered and start going for the data . . . RWPower MOVE.W Track(A1,D1),D6 ; set speed for last track read . . . BSR RWPowerUp ; turn on drive and delay until powered eject ; ;_______________________________________________________________________ ; ; Routine: GetTrack ; Arguments: (input): disk is powered and selected ; (output): SideTrack - set to next track to process ; FirstSect - first sector on that track we need ; SectMap - bit map of sectors on that track we need ; FBlksDone - number of blocks done prior to this track ; DiskBuffer - points to point in buffer 4 this track ; RecalCnt - initialized to number of recals per trk ; Called By: this is really DiskPrime, part II ; Function: This code is executed before reading or writing the data ; on a single track. ;_______________________________________________________________________ GetTrack MOVE.L DiskUnitPtr(A1),A2 ; Device Ctl Entry ptr MOVE.L DCtlQHead(A2),A0 ; current request ptr MOVE.L DCtlPosition(A2),D0 ; current byte position MOVEQ #9,D7 ; LSR.L D7,D0 ; convert to block number (div by 512) ; at this point: ; A0 = user request parameter blk ptr ; A1 = disk locals ptr ; A2 = disk driver DCE ptr ; D1 = drive locals offset ; D0 = absolute diskette block number ; D7 = 9 (2^9=512) ; ; now figure out the next track number we need, the first sector number we want ; on this track and the bitmap of sectors we want from this track/side . . . TST.B mfmDisk(A1,D1) ;Is this an MFM disk? BMI mGetTrack ;-> yes, sector layout is different MOVEQ #0,D4 ; 0 = 1-sided format = side 0 TST.B TwoSideFmt(A1,D1) ; BEQ.S @1 ; MOVEQ #1,D4 ; 1 = 2-sided format = side 1 @1 MOVEQ #100,D2 ; LSL #3,D2 ; D2 = 800 LSL D4,D2 ; block #, end of disk CMP.L D2,D0 ; block number past end of disk block? BLT.S NxtClass ; br if not DskParmErr MOVEQ #ParamErr,D0 ; disk position parameter too high ToDRWOff BRA.S DskRWOff ; exit, activating power-down task NxtClass MOVEQ #7,D3 ; 8 blks/track in last speed class LSL #4,D3 ; 128 blks/side in last speed class LSL D4,D3 ; blks in last speed class MOVEQ #16,D5 LSL D4,D5 ; next speed class has 16-32 more blks @1 ADD D5,D3 ; next lower speed class has more blks SUB.L D3,D2 ; first blk #, this spd class CMP.L D2,D0 ; BLT.S @1 ; br if blk in a lower speed class NxtTrack LSR #4,D3 ; blks/cylinder MOVEQ #-1,D5 ; will hold trk offset, this speed class @1 ADD D3,D2 ; first blk # next track ADDQ #1,D5 ; CMP D2,D0 ; BGE.S @1 ; loop until past track LSR D4,D3 ; blks per track, this speed class MOVEQ #12,D6 ; SUB D3,D6 ; LSL #4,D6 ; first track this speed class ADD D6,D5 ; the track we're on! MOVE.L D4,D6 ; side SUB D3,D2 ; first blk#, this track CMP.L D2,D0 ; BGE.S @2 ; br if on this track SUB D3,D2 ; must be side 0 of 2-sided cylinder MOVEQ #0,D6 ; @2 gtResume ;This is where mGetTrack returns TST.B D6 ; side 1 or side 0? BEQ.S @3 ; br if side 0 BSET #11,D5 ; set for side 1 TST.B Sides(A1,D1) ; do we have a 2-sided drive? BNE.S @3 ; br if so MOVEQ #twosideErr,D0 ; can't read it on a 1-sided drive BRA.S ToDRWOff ; exit, activating power-down task @3 MOVE.W D5,SideTrack(A1) ; side/track we want to be on SUB D2, D0 ; first sector this track SUB D0, D3 ; sectors left this track MOVE.W D0,FirstSect(A1) ; MOVE.L IOByteCount(A0),D5 ; get # of bytes requested MOVE.L IONumDone(A0),D2 ; get # of bytes already done SUB.L D2,D5 ; minus the ones we processed already LSR.L D7,D5 ; round down to nearest sector BEQ.S DskParmErr ; uneven parameter error . . . ; D5 = number of sectors (blocks) we have to go ; D3 = number of sectors still left on this track CMP.W D5,D3 ; want all remaining sectors this trk? SLT D6 ; D6=$00 if it's the last track to do <24Oct85> BLE.S @4 ; branch if so MOVE.W D5,D3 ; number of sectors to get this track ; at this point: ; A0 = ptr to user request parameter blk ; (A1,D1) = ptr to drive locals ; A2 = ptr to disk driver DCE ; D0 = first 'track sector' to get this track ; D2 = IONumDone ; D3 = number of sectors to get this track ; D6 = $00 if this is the last track we have to do <24Oct85> ; D7 = 9 ; FirstSect = first sequential sector number we want this track @4 MOVEQ #0,D5 ; sector bit map MOVE.W D0,D4 ; save 1st sector number and sector <24Oct85> MOVE.W D3,-(SP) ; count for cache check <24Oct85> @5 BSET D0,D5 ; one bit is always set for FirstSect ADDQ.W #1,D0 ; incr to next sector number SUBQ.W #1,D3 ; decr number of sectors needed BNE.S @5 MOVE.W (SP)+,D3 ; restore sector count <24Oct85> MOVE.L D5,SectMap(A1) ; keep sector bitmap around MOVE.L IOBuffer(A0),A3 ; get pointer to user buffer <24Oct85> ADD.L D2,A3 ; add IONumDone <24Oct85> MOVE.L A3,DiskBuffer(A1) ; start buf addr, 1st sector this trk <24Oct85> LSR.L D7,D2 ; figure file blocks done so far MOVE.W D2,FBlksDone(A1) ; and save (for file tag writes) MOVE.B RecalInit(A1),RecalCnt(A1) ; one recal per track ; OK, it's time to check whether our track cache (if any) has the blocks we need ; ; A0 = ptr to user request parameter blk ; (A1,D1) = ptr to drive locals ; A2 = ptr to disk driver DCE ; A3 = start buf addr for 1st sector this track ; D3 = sector count this track ; D4 = first 'track sector' to get this track ; D5 = bitmap of needed track sectors ; D6 = $00 if this is the last track we have to do <24Oct85> ; D7 = 9 ; FirstSect = first sequential sector number we want this track CheckCache ; cache cache ; valid read installed action ; ; dc dc no reset TCRdEnable (TCRdEnable,TCInstalled both zero) ; no no yes reset TCRdEnable (preserve cache for a different track) ; no yes yes if sync call and no sectors needed on another track, ; set TCRdEnable and init cache for this drive/track/side. ; yes no yes reset TCRdEnable invalidate cache for written sectors ; yes yes yes get appropriate sectors from cache; if sync call, ; and no sectors needed on another track, set TCRdEnable. ; If verify, skip cache always. CLR.B TCRdEnable(A1) ; assume we won't be caching this RWT <24Oct85> BSR CheckRead ; is this a read call? BEQ.S readCache ; br if so BSR CacheValid ; do we have a valid cache? BNE.S toReSeek ; continue with RWT if not MOVE.L D5,D0 ; get bitmap of sectors we are writing NOT.L D0 ; form bitmap of those we aren't writing AND.L D0,TCSectMap(A1) ; invalidate those sectors we write ; BSR TCRdEnbChk ; reads into cache if sync call, last trk toReSeek BRA ReSeek ; continue with RWT (MIGHT WANT TO ENABLE CACHE READS?) readCache TST.B DskVerify ; read-verify? <25Oct85> BNE.S toReSeek ; skip caching if so <25Oct85>' BSR CacheValid ; do we have a valid cache? BNE rdCacheNV ; br if not MOVE.L D5,D2 ; get bitmap of sectors we are reading AND.L TCSectMap(A1),D2 ; see if we have any currently cached BEQ rc_Cont ; br if not . . . MOVEQ #2,D7 ; number of bytes/sector ASL.L #8,D7 ; (cheap way to make 512) MOVE.W D4,D0 ; first sector needed this track TST.B mfmDisk(A1,D1) ;Is this an MFM disk? BPL.S @00 ; SUBQ.W #1,D0 ;Yes, the buggers start with sector 1 @00 ; not sector zero!!! MULU #524,D0 ; offset into cache buffer MOVE.L TCBuffer(A1),A4 ; get track cache buffer ptr ADD D0,A4 ; track cache buffer for first sector rc_Loop BTST D4,D2 ; do we have and need this sector? BEQ.S @3 ; br if not BCLR D4,D5 ; mark it got in sector map MOVEM.L A0-A1,-(SP) ; preserve regs over blockmove TST.L TagBufPtr(A1) ; do we have a separate tag buffer? BEQ.S @1 ; br if not (transfer to low-mem) MOVE.W D4,D0 ; current sector SUB.W FirstSect(A1),D0 ; relative sector number this track ADD.W FBlksDone(A1),D0 ; blocks done so far MULU #12,D0 ; offset into caller's tag buffer MOVE.L TagBufPtr(A1),A1 ; separate tag buffer ADD.L D0,A1 ; ptr into it BRA.S @2 ; transfer the tags @1 LEA TagData+2,A1 ; copy them to low-memory @2 MOVE.L A4,A0 ; track cache MOVE.L (A0)+,(A1)+ ; transfer tags MOVE.L (A0)+,(A1)+ MOVE.L (A0)+,(A1)+ MOVE.L A3,A1 ; user buffer address MOVE.L D7,D0 ; 512-byte blockmove _BlockMove ; transfer data MOVEM.L (SP)+,A0-A1 ADDQ.W #1,TCNumUsed(A1) ; increment cache usage count <25Oct85> ADD.L D7,DCtlPosition(A2) ; bump position (not accurate until done) ADD.L D7,IONumDone(A0) ; bump number done @3 ADD.L D7,A3 ; bump user buffer address ADD.L D7,A4 ; bump track cache buffer address ADD #12,A4 ; (track cache includes tags) ADDQ.W #1,D4 ; incr to next sector number SUBQ.W #1,D3 ; decr number of sectors needed BNE.S rc_Loop ; go again if not done MOVE.L D5,SectMap(A1) ; update sector bitmap BNE.S rc_Cont ; br if not finished with this track MOVE.L IONumDone(A0),D0 ; bytes done so far CMP.L IOByteCount(A0),D0 ; more to do? BLT GetTrack ; loop if more to do MOVEQ #0,D0 ; success! BRA DskRWOff ; sayonara rc_Cont BSR.S TCRdEnbChk ; enable reads into cache if sync call, last track BRA.S ReSeek ; continue with RWT rdCacheNV BSR.S TCRdEnbChk ; enable reads into cache if sync call, last track BNE.S ReSeek ; continue with RWT if not MOVE.W Drive(A1),TCDrive(A1) ; initialize cache MOVE.W SideTrack(A1),TCSideTrack(A1) ; current side and track CLR.L TCSectMap(A1) ; no sectors so far BRA.S ReSeek ; and on to RWT ; TCRdEnbChk checks whether this is a synchronous call and we're on the last track TCRdEnbChk ; <22Oct85> TST.B TCInstalled(A1) ; installed and enabled? BEQ.S @2 ; exit if not BTST #AsyncTrpBit,Command(A1) ; async bit on? BNE.S @1 ; br if so TST.B D6 ; more sectors needed on another track? @1 SEQ TCRdEnable(A1) ; activate reads into cache if sync, last track RTS ; BEQ for sync, last track, enabled @2 MOVEQ #1,D6 ; force NE BRA.S @1 ; CacheValid checks to see if the cache is valid for current drive/side/track CacheValid ; <22Oct85> TST.B TCInstalled(A1) ; installed and enabled? BEQ.S @1 ; exit if not MOVE.W TCDrive(A1),D0 ; get cache drive BEQ.S @1 ; br if not valid CMP.W Drive(A1),D0 ; same drive? BNE.S @1 ; br if not MOVE.W SideTrack(A1),D0 ; get track side/track SUB.W TCSideTrack(A1),D0 ; current side and track match? BEQ.S @2 ; br if cache is set up @1 MOVEQ #-1,D0 ; not valid @2 RTS ; BEQ for valid eject ; ;_______________________________________________________________________ ; ; Routine: ReSeek ; Arguments: (input): disk is powered and selected ; SideTrack - set to next track to process ; FirstSect - first sector on that track we need ; SectMap - bit map of sectors on that track we need ; FBlksDone - number of blocks done prior to this track ; DiskBuffer - points to point in buffer 4 this track ; RecalCnt - initialized to number of recals per trk ; (output): nothing ; Called By: this is DiskPrime, part III ; Function: Seek to the desired track; check the speed at the track if ; it's time, and adjust it if necessary. ;_______________________________________________________________________ ReSeek MOVE.L JReSeek,-(SP) RTS jtReSeek MOVE.B BadSpdInit(A1),BadSpdCnt(A1) ; seek (asynchronously) to get to the right track (seek handles the case where ; we are already at the right track . . .) ReSeek1 MOVE.W SideTrack(A1),D6 ; seek . . . BSR Seek BMI.S toDoRecal ; (to DoRecal) recal on errors <25Oct85> MOVE.B ReadErrInit(A1),ReadErrCnt(A1) BRA.S OnTrack ; skip track speed check for NuMac toDoRecal BRA DoRecal ; recal eventually . . . <25Oct85> eject ; ;_______________________________________________________________________ ; ; Routine: OnTrack ; Arguments: (input): disk is powered and selected ; SideTrack - set to next track to process ; FirstSect - first sector on that track we need ; SectMap - bit map of sectors on that track we need ; FBlksDone - number of blocks done prior to this track ; DiskBuffer - points to point in buffer 4 this track ; RecalCnt - initialized to number of recals per trk ; (A1,D1) - points at drive variables ; (output): DCtlPosition - updated by bytes processed ; IONumDone - updated by bytes processed ; SectMap - cleared ; Called By: this is DiskPrime, part IV ; Function: Read each address mark as it passes under the head; if that ; sector is needed, read or write it as desired and pass any ; poll data on to the serial driver. ; ; Note: as a sector passes over the r/w head, the current file block and ; tag buffer pointers are figured so: ; ; current file block = FirstFSeq + FBlksDone + (sector-FirstSect) ; tag buffer pointer = [FBlksDone + (sector-FirstSect)] * 12 ;_______________________________________________________________________ OnTrack MOVE.B WrgSectInit(A1),WrgSectCnt(A1) ; addr mark misses we tolerate ; At this point, we should be on the right track. Read the next ; address mark to see where we are. RdAddr sets interrupt level 3. OnTrack1 MOVE.W D1,D6 ; preserve drive offset <24Oct85> BSR RdAddrSetup ; set up for and call RdAddr BMI AdrDtaErr ; process stack data, go to AdrDtaErr <24Oct85> CMP.W SideTrack(A1),D1 ; are we on the right track and side? BNE WrgSideTrk ; <24Oct85> MOVE.B D3,gcrFmtByte(A1) ; save format byte for the duplicator <1.8> MOVE.W D2,CurSector(A1) ; save the sector number <22Oct85> MOVE.W D2,TagData ; set up TagData+1 for writes MOVE.L SectMap(A1),D0 ; sector bitmap of needed sectors BTST D2,D0 ; do we need this sector? BNE OTSetUp ; br if so . . . normal r/w path <24Oct85> TST.B TCRdEnable(A1) ; are we reading into a cache? <22Oct85> BEQ WrgSectAdr ; go to WrgSectAdr if not <24Oct85> MOVE.L TCSectMap(A1),D0 ; see if we have it in the cache yet <24Oct85> BTST D2,D0 ; <24Oct85> @toWrgSectAdr ;
BNE WrgSectAdr ; go to WrgSectAdr if so <24Oct85> LEA jtRdData,A0 ; no, use the normal rdData routine

CMP.B #-2,isSWIM(A1) ; Check for presence of SWIM2

BNE.S @NotSWIM2 ;

LEA jtISMRdData,A0 ; yes, use the SWIM2 rdData routine

@NotSWIM2 ;

CMP.L JRdData,A0 ; has been replaced or prefixed --- <03Nov85> SNE TCRdEnable(A1) ; i.e., this is a copy-protection <31Oct85> BNE WrgSectAdr ; check . . . skip cache if so <31Oct85> MOVE.W D2,D1 ; sector number <24Oct85> TST.B mfmDisk(A1,D6) ;Is this an MFM disk? BPL.S @00 ; SUBQ.W #1,D2 ;Yes, the buggers start with sector 1 ; not sector zero!!! BMI.S @toWrgSectAdr ; don't cache sector zero!!
@00 ; MULU #524,D2 ; tag/data offset into track cache buf <24Oct85> MOVE.L TCBuffer(A1),A0 ; buffer start <24Oct85> ADD.L D2,A0 ; add in offset to tag/data <24Oct85> ADD #12,A0 ; skip over tags to data <24Oct85> BSR RdData ; read the data mark <24Oct85> BSR GetDrv1 ;get A1,D1 back MOVE.W D1,D6 ; and save the drive vars offset in D6 TST.W D0 ;reset the CCR with RdData's result SPL TCRdEnable(A1) ; turn off cache this trk on errors <29Oct85> BMI.S @1 ; ignore errors (may be copy-prot sect) <24Oct85> ADDQ.W #1,TCNumCached(A1) ; increment cache activity count <25Oct85> MOVE.W CurSector(A1),D2 ; get sector number we read <24Oct85> MOVE.L TCBuffer(A1),A0 ; buffer start <24Oct85> MOVE.W D2,D1 ; sector number <24Oct85> TST.B mfmDisk(A1,D6) ;Is this an MFM disk? BPL.S @01 ; SUBQ.W #1,D1 ;Yes, the buggers start with sector 1 @01 ; not sector zero!!! MULU #524,D1 ; tag offset into track cache buffer <24Oct85> ADD.L D1,A0 ; add in offset to tag/data this sect <24Oct85> LEA TagData+2,A2 ; <24Oct85> MOVE.L (A2)+,(A0)+ ; transfer tag data from low memory <24Oct85> MOVE.L (A2)+,(A0)+ ; <24Oct85> MOVE.L (A2)+,(A0)+ ; <24Oct85> MOVE.L TCSectMap(A1),D4 ; get the cache sector map <24Oct85> BSET D2,D4 ; flag it as valid <24Oct85> MOVE.L D4,TCSectMap(A1) ; update the map <24Oct85> @1 BSET #7,IntFlag ; do we need to open up ints for <24Oct85> BNE.S @2 ; AppleTalk? br if not . . . <24Oct85> MOVE.W SectTime(A1),D0 ; set up timer for 1 sector time <25Oct85> TST.B mfmDisk(A1,D6) ;Are we in MFM mode? BPL.S @11 ;-> no MOVEQ #MFMSectTime,D0 ;MFM sectors have a fixed gap size @11 ; BSR WakeSetUp ; return immediately <25Oct85> BSR EmptyPD ; process stack data <25Oct85> BSR WakeGo ; do the wait (and enable ints) <25Oct85> BRA.S @3 @2 BSR EmptyPD ; process stack data <24Oct85> ANDI #$F8FF,SR ; open for SCC/VIA ints <24Oct85> @3 BRA OnTrack ; now try for the real data <24Oct85> OTSetUp CMP.B #$1F,D3 ; set format type SGT TwoSideFmt(A1,D6) ; and save it to distinguish 2-sided disks SUB.W FirstSect(A1),D2 ; relative sector number this track MOVE.W D2,D1 ASL.L #8,D1 ADD.L D1,D1 ; sector # times 512 ADD.L DiskBuffer(A1),D1 ; add in buffer start MOVE.L D1,A0 ; data buffer pointer MOVE.W FBlksDone(A1),D1 ; blocks done so far ADD.W D2,D1 ; relative block number MOVE.W D1,D0 ; save for write case ADD.W D1,D1 ; double ADD.W D0,D1 ; x3 ASL.W #2,D1 ; x12 gives us offset into buffer MOVE.W D1,TagBufOS(A1) ; save in case of read BSR CheckRead ; is it a read? BEQ.S OTRead ; br if so ; it was a write request so call write data mark OTWrite MOVE.L TagBufPtr(A1),D3 ; tag buffer start BEQ.S @1 ; br if no separate buffer MOVE.L D3,A1 ; tag buffer start ADD.W D1,A1 ; point to appropriate tag LEA TagData+2,A2 MOVE.L (A1)+,(A2)+ MOVE.L (A1)+,(A2)+ MOVE.L (A1)+,(A2)+ ; fill it in BRA.S @2 ; and do the write @1 ADD.W FirstFSeq(A1),D0 ; figure relative file block number MOVE.W D0,TagData+8 ; so we can write it out in tag field @2 BSR WrData ; WrData timestamps it BMI AdrDtaErr ; go to AdrDtaErr on errors BRA.S GotSect ; ; it was a read request so call read data mark OTRead BSR RdData ; read the data mark BMI AdrDtaErr ; go to AdrDtaErr on errors MOVE.L SonyVars,A1 MOVE.L TagBufPtr(A1),D0 ; do we have a separate tag buffer? BEQ.S GotSect ; br if not MOVE.L D0,A0 ; point to tag buffer start ADD.W TagBufOS(A1),A0 ; and then to appropriate entry LEA TagData+2,A2 MOVE.L (A2)+,(A0)+ MOVE.L (A2)+,(A0)+ MOVE.L (A2)+,(A0)+ ; transfer tag data from low memory ; We got the sector so flag it as gotten, update our counts and ; then try for the next one GotSect BSR GetDrv1 ; get A1, D1 <25Oct85> MOVE.L SectMap(A1),D4 ; get the map MOVE.W CurSector(A1),D2 ; get r/w sector number <22Oct85> BCLR D2,D4 ; flag it as gotten MOVE.L D4,SectMap(A1) ; update the map MOVE.L DiskUnitPtr(A1),A2 ; get pointer to DCE MOVE.L DCtlQHead(A2),A0 ; get pointer to user request block MOVEQ #2,D3 ; number of bytes/sector ASL.L #8,D3 ; (cheap way to make 512) ADD.L D3,DCtlPosition(A2) ; bump position (not accurate until done) ADD.L D3,IONumDone(A0) ; bump number done <24Oct85> MOVE.L IOByteCount(A0),D3 ; original request <24Oct85> SUB.L IONumDone(A0),D3 ; D3 = 0 if we're done (save for later) <24Oct85> ; done r/w NewIntf Atalk action <2.1> ; ; dc dc dc yes 10 ms sector wait ; yes read dc no continue (to next track) ; no read dc no continue (may get 1-1) ; yes write dc no 700 us wait for erase head off ; no write yes no continue (may get 1-1) ; no write no no 10 ms sector wait (1-1 not possible) BSET #7,IntFlag ; do we need to open up ints for <24Oct85> BEQ.S @1 ; AppleTalk? br if so . . . <24Oct85> BSR.S CheckRead ; is it a read? <24Oct85> BEQ.S @2 ; br if so <24Oct85> TST.L D4 ; last sector on this track/side? <24Oct85> BNE.S @0 ;-> no <2.1> BSR.S EmptyPD ; process stack data <25Oct85> MOVEQ #7,D0 ; wait 700 usec after last sector write <24Oct85> BSR WakeUp ; wake up when it's over <24Oct85> BRA.S @3 ; <25Oct85> @0 TST.B NewIntf(A1,D1) ; is this a new interface drive <2.1> BMI.S @2 ;-> yes, no waiting (we might do 1-1) <2.1> @1 MOVE.W SectTime(A1),D0 ; set up timer for 1 sector time <25Oct85> TST.B mfmDisk(A1,D1) ;Are we in MFM mode? <2.1> BPL.S @11 ;-> no MOVEQ #MFMSectTime,D0 ;MFM sectors have a fixed spacing @11 ; BSR WakeSetUp ; return immediately <25Oct85> BSR.S EmptyPD ; process stack data <25Oct85> BSR WakeGo ; do the wait (and enable ints) <25Oct85> BRA.S @3 ; then continue <25Oct85> @2 BSR.S EmptyPD ; process stack data <25Oct85> ANDI #$F8FF,SR ; open for SCC/VIA ints <25Oct85> @3 MOVE.L D4,D0 ; sector map (set D0=0 for exit case) <25Oct85> BNE OnTrack ; br if there's more on this track ; we're all done with this track. See if there is anything else to do TST.L D3 ; bytes to go <24Oct85> BGT GetTrack ; loop if more to do <24Oct85> TST.B TwoSideFmt(A1,D1) ; 2-sided format? <02Sep85> BEQ.S ToDskRWOff ; br if not <02Sep85> TST.B Sides(A1,D1) ; we better have a 2-sided drive? <02Sep85> BNE.S ToDskRWOff ; br if so <02Sep85> MOVEQ #twoSideErr,D0 ; give an early warning! <02Sep85> ToDskRWOff BRA DskRWOff ; jump to IODone to tell the OS we're finished. CheckRead CMP.B #ARdCmd,Command+1(A1) ; is it a read? RTS eject ; ;______________________________________________________________________________; ; ; routine to call polldata process procedure if there is one, ; or reset the stack if there isn't . . . ;______________________________________________________________________________; EmptyPD MOVE.L (SP)+,A4 ; save return address PEA @2 ; this routine's return address MOVE.L PollProc,-(SP) ; is there a proc to process poll data? BEQ.S @1 ; br if not MOVE.L SonyVars,A1 MOVEM.L D0/D2-D3/A0/A4,SaveRegs(A1) ; save some regs RTS ; go to it! @2 BSR GetDrv1 MOVEM.L SaveRegs(A1),D0/D2-D3/A0/A4 JMP (A4) @1 MOVE.L PollStack,SP ; otherwise, throw away any data BSR GetDrv1 JMP (A4) ;______________________________________________________________________________; ; ; Here is the exception handling code . . . these routines are branched to from ; OnTrack with interrupts disabled and data possibly on the stack. ;______________________________________________________________________________; AdrDtaErr BSR.S EmptyPD ; process stack data <24Oct85> ANDI #$F8FF,SR ; restore interrupts ADDQ.W #1,DiskErrs(A1) ; increment global soft-error count TST.B DisableRetries(A1) ; are we supposed to do retries? BEQ.S @Done ; -> yes CLR.B ReCalCnt(A1) ; perform no recals CLR.B ReadErrCnt(A1) ; or read retries @Done ; ADDQ.W #1,DriveErrs(A1,D1) ; increment drive soft-error count <25Oct85> TST.B ReCalCnt(A1) ; down to last recal? <22Oct85> BEQ.S @1 ; br if so (retry rather than fail) <22Oct85> BSR.S CheckRead ; write? <22Oct85> BNE.S DoRecal ; br if so (may be slightly off-track) <22Oct85> @1 SUBQ.B #1,ReadErrCnt(A1) ; bad addr, data mk - decrement error cnt BPL OnTrack ; try for another BRA.S DoRecal ; <24Oct85> ; we don't need this one so figure out how long it will take for one we do need ; to pass under the head and give the time back to the user ; (for now, just wait for most of this sector to pass) WrgSectAdr MOVE.L SonyVars,A1 ; get A1 <25Oct85> MOVE.W SectTime(A1),D0 ; set up timer for 1 sector time <25Oct85> TST.B mfmDisk(A1,D6) ;Are we in MFM mode? BPL.S @1 ;-> no MOVEQ #MFMSectTime,D0 ;MFM sectors have a fixed gap size @1 ; BSR WakeSetUp ; return immediately <25Oct85> BSR.S EmptyPD ; process stack data <25Oct85> BSR WakeGo ; do the wait (and enable ints) <25Oct85> ADDQ.L #1,RndSeed ; bump our random seed MOVEQ #SectNFErr,D0 ; in case we run out of recals <24Oct85> SUBQ.B #1,WrgSectCnt(A1) ; enough already? BMI.S DoRecal ; if so, recal BRA OnTrack1 ; then continue search WrgSideTrk BSR.S EmptyPD ; process stack data <24Oct85> MOVEQ #SeekErr,D0 ; in case we run out of recals <24Oct85> ; fall through to DoRecal <24Oct85> ;______________________________________________________________________________; ; ; if we can't get an address mark (with retries) we must try to recalibrate ; DoRecal recals to track 0 and then refigure speed codes. ;______________________________________________________________________________; DoRecal ANDI #$F8FF,SR ; restore interrupts SUBQ.B #1,ReCalCnt(A1) ; did we recal yet? BLE.S @1 ; if so, give up BSR Recal ; recal to track 0 BMI.S @1 ; exit on errors BSR MakeSpdTbl ; and redetermine speeds BPL ReSeek @1 BRA.S ToDskRWOff ; we ran out of retries so give up and ; return an error