; ; File: SonyDup.a ; ; Contains: Extensions to the Sony driver for Apple 3.5" Disk Duplicator Support ; ; Written by: Steve Christensen ; ; Copyright: © 1988-1992 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 12/14/92 RC Restore Pre-PDM D2 with Horror Roll in ; 12/7/92 rab Roll in Horror changes. Comments followÉ ; <5> 11/14/91 SWC Converted the SCC polling code to a macro (in SonyHdr.a) so it's ; easier to overpatch. ; <2> 10/18/91 CMP Added support for SWIM2. Also, in DoFmtCopy, put read of error ; register after the other SWIM setup stuff so that it REALLY gets ; cleared. ; 12/02/92 HY Added hasPwrControls conditional. ; 10/18/92 CCH Added nop's for systems with non-serial writes to IO space. ; <7> 7/14/92 CSS Fixed the comment below so an exact version of this ; file could be copied into SuperMario. ; <6> 4/27/92 JSM Get rid of conditionals: hasPowerMgr, hasPwrControls, ; supportsMFM, and isUniversal 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. ; <5> 1/21/91 SWC Cleaned up the header comments. ; <4> 9/21/90 BG Removed <3>. 040s are behaving more reliably now. ; <3> 6/18/90 CCH Added NOPs for flaky 68040's. ; <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.5> 6/6/89 SWC Just fixed the comment describing CtlFmtCopy's input parameters ; to reflect reality. ; <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 SWC/Fixed a bug in MFM format: didn't allow enough time before ; switching heads. Added a status call to return the duplicator ; version this driver supports. Increased default GapSync from 7 ; to 8, to allow more optimal sector spacing, and more margin if 1 ; to 1 writes are attempted. ; <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.1> 9/29/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.0> 9/19/88 GGD Steve Christensen's disk duplicator additions to the Sony Driver. ; 9/12/88 SWC Added index mark stuff to MFM format as in SonyMFM. ; 9/2/88 SWC Added an option to CtlFmtCopy to just format (Cork asked). ; <1.8> 8/23/88 SWC Added this file into Sony driver sources. ; ;______________________________________________________________________________ ; ; This file contains all routines necessary to add support for DiskCopy ; (Apple's disk duplication software) to the standard Sony driver. These ; routines are built into Mac IIci and newer ROMs, and are installed by ; DiskCopy as a RAM-based driver for Macs that don't have the support built in. ;______________________________________________________________________________ title 'File: SonyDup.a' BLANKS ON STRING ASIS ;_______________________________________________________________________ ; ; Routine: DupVersion ; ; Inputs: A0 -- pointer to csParam field of user's parameter block ; A1 -- pointer to SonyVars ; D1 -- offset to drive's private variables ; ; Outputs: D0 -- result code (always zero) ; ; Function: Returns the duplicator version that this driver supports. ; This is so that common features are properly matched. ;_______________________________________________________________________ DupVersion MOVE.W #$0410,(A0) ;current version is 4.1 MOVEQ #0,D0 BRA DiskDone ;_______________________________________________________________________ ; ; Routine: GetFmtByte ; ; Inputs: A0 -- pointer to csParam field of user's parameter block ; A1 -- pointer to SonyVars ; D1 -- offset to drive's private variables ; ; Outputs: D0 -- result code (always zero) ; ; Function: Returns the format byte from the last address field read so ; that we can determine what the interleave is for 800K disks. ; This call can also be used to determine if the RAM-based ; Disk Duplicator version of the driver is installed. ;_______________________________________________________________________ GetFmtByte MOVE.B gcrFmtByte(A1),(A0) MOVEQ #0,D0 BRA DiskDone ;_______________________________________________________________________ ; ; Routine: CtlFmtCopy ; ; Inputs: A0 -- pointer to user's parameter block ; csParam+ 0: format type (0=400K, 1=800K, 2=720K, 1=1440K[HD]) <2.5> ; csParam+ 2: pointer to user data buffer <2.5> ; csParam+ 6: pointer to tag data buffer <2.5> ; csParam+10: format byte ($12=Mac 400K, $22=Mac 800K, $24=Apple II 800K) <2.5> ; csParam+11: if ­0 then also verify each track <2.5> ; A1 -- pointer to SonyVars ; D1 -- offset to drive's private variables ; ; Outputs: D0 -- result code (0 if correctly formatted) ; ; Function: Formats, copies [and verifies] each track on a disk in one ; pass for the Apple 3.5" Floppy Disk Duplicator program. ;_______________________________________________________________________ ; offsets into our private fmtParams(A1) block [really at csParam(A0)] fDataBuf EQU 0 ;user data fTagBuf EQU fDataBuf+4 ;tag data fFmtByte EQU fTagBuf+4 ;format byte fDoVerify EQU fFmtByte+1 ;whether or not to verify also CtlFmtCopy BNE DiskDone ;-> no drive installed so exit with error SUB #512,SP ;get space for buffers we need off stack MOVE.L SP,DiskBuffer(A1) ;StackBuf for mark, block buffer IF hasPwrControls THEN ; TestFor hwCbPwrMgr BEQ.S @pmgrdone BSR TurnIWMon ;Turn IWM on with pmgr call @pmgrdone ENDIF ; LEA csParam+2(A0),A0 MOVE.L A0,fmtParams(A1) ;(save this address for later) MOVE.W -(A0),D4 ;Use current format? BEQ.S @0 ;-> yes, don't change anything MOVEQ #numSDFmts-1,D3 ;Assume no SWIM or SuperDrive MOVE.B isSWIM(A1),D0 ;Is a SWIM connected AND AND.B mfmDrive(A1,D1),D0 ; is this a SuperDrive? BPL.S @00 MOVEQ #numSDFmts,D3 ;Yes, we can do MFM!! TST.B twoMegFmt(A1,D1) ;Is this a double-density disk? BPL.S @00 MOVEQ #numDDFmts,D3 ;Yes, it must be 1440K @00 MOVEQ #paramErr,D0 ;Assume format type is outta range CMP.W D3,D4 ;Well, is it? BHI FmtCopyExit ;-> yep, just exit CMPI.W #NumSDFmts,D4 ;(thanks, Mr. Davidian, sir) SEQ D0 ;MFM format if it's the last SD one OR.B twoMegFmt(A1,D1),D0 ; or it's double-density? SMI mfmDisk(A1,D1) @0 TST.B isSWIM(A1) ;Is a SWIM installed? BPL.S @01 ;-> no, skip BSR SetChipMode ;Set up the mode for MFM or GCR BNE FmtCopyExit ;-> couldn't initialize the chip @01 BSR DiskSelect ;Re-select the interface TST.B mfmDisk(A1,D1) ;Are we in MFM mode? SMI TwoSided(A1) BMI.S @1 ;-> yes, we're 2-sided TST.B Sides(A1,D1) ;for now, format according to drive SMI TwoSided(A1) ;$00 for 1-sided format BPL.S @1 ;-> one-sided SUBQ.W #1,D4 ;format 2-sided as 1-sided? BNE.S @1 ;-> no CLR.B TwoSided(A1) ;force one-sided @1 TST.B TwoSided(A1) ;so, 1-sided or 2-sided? SNE TwoSideFmt(A1,D1) ;update it for future interested parties... MOVE.W #8,GapSync(A1) ; start with 8 sync groups before sector <2.1> BSR FVPowerUp ; start up the drive (synchronously) MOVEQ #WrProtAdr,D0 ;Is the disk write-protected? BSR AdrAndSense BMI.S @11 ;-> nope, onward! MOVEQ #wPrErr,D0 ;Return a write-protect error BRA.S FmtCopyExit ;someone OBVIOUSLY wasn't checking-- @11 ;(massive finger pointing--Scott?) MOVE.L SonyVars,A1 MOVE.L DiskBuffer(A1),A0 ;now fill stack buffer with blank marks MOVEQ #12-1,D0 ;marks for 12 sectors @2 MOVEQ #36-1,D1 ;36 bytes per sector LEA AdrMkTbl,A1 ;point A1 to blank image @3 MOVE.B (A1)+,(A0)+ DBRA D1,@3 DBRA D0,@2 BSR GetDrv1 CLR.W SideTrack(A1) ;start with track 0 @TrackLoop BSR SpdSeek ;seek to track and adjust speed if needed BNE.S FmtCopyExit ;exit on errors BSR GetDrv1 TST.B mfmDisk(A1,D1) ;Are we in MFM mode? BPL.S @40 ;-> no, do the regular format BSR mFmtCopyTrk ;Format/Copy/Verify the track (MFM style) BRA.S @4 @40 BSR gFmtCopyTrk ;Format/Copy/Verify the track (GCR style) @4 BNE.S FmtCopyExit ;exit on errors BSR GetDrv1 BCLR #3,SideTrack(A1) ;clear 'side' bit ADDQ #1,SideTrack(A1) ;go on to the next track CMP #80,SideTrack(A1) ;until we're done with all 80 BLT.S @TrackLoop FmtCopyOK MOVEQ #0,D0 ;successful exit FmtCopyExit ADD #512,SP ;clean up the stack BRA DskRWOff ;Share SonyRWT exit routine ;(sets up the power down time) eject ;_______________________________________________________________________ ; ; Routine: gFmtCopyTrk ; ; Inputs: SideTrack contains the current side and track number ; ; Outputs: D0 -- result code (0 if format ok) ; ; Function: This routine formats and copies a track (both sides for ; double-sided disks), verifying that sync is evenly spread ; between the sectors, then verifies the format. It will ; format both Macintosh (2-1 interleave) and Apple II (4-1 ; interleave) disks. ;_______________________________________________________________________ gFmtCopyTrk BSR GetDrv1 MOVE.W SideTrack(A1),D6 ; current side/track BSR FillMarks ; update mark buffer for this track/side @FmtTrk1 BSR gDoFmtCopy ; format the track (disables interrupts) BEQ.S @1 ; br if ok ANDI #$F8FF,SR ; open up interrupts BRA @FTExit ; exit immediately for write errors ; now we check the intersector gap... @1 BSR GetDrv1 BSR RdAddrSetup ; get next address mark BMI.S @2 ; br if error TST.B D2 ; should be sector 0 BEQ.S @2 MOVEQ #Fmt1Err,D0 ; set "not sector 0" error otherwise @2 BSR toEmptyPD ; get rid of poll data (saves D0 in DskErr)) ANDI #$F8FF,SR ; open up interrupts LEA GapSync(A1),A0 ; useful addr MOVE.W DskErr,D0 ; check error code BMI.S @DecrSn1 ;-> error (change amt of sync in case erase turn-off ; glitched us out or not sector 0--too much sync) MOVE.L #MustFindCt+4,D2 ; nibble must find count, adjusted SUB.W D0,D2 ; nibble gap before sector 0 DIVU #5,D2 ; sync group count MOVEQ #Fmt2Err,D0 ; assume "not enuf sync" SUB.W (A0),D2 ; groups more than the standard GapSync BMI.S @DecrSync ; br if too little EXT.L D2 DIVU SectCnt(A1),D2 ; divide by groups per sector BEQ.S @FTExitOK ; br if ok SUBQ.W #1,D2 ; don't increase if only by 1 BEQ.S @FTExitOK ADDQ.W #1,(A0) ; increase GapSync by 1 only @FTExitOK BSR GetDrv1 ; set A1,D1 to point to drive vars MOVEA.L fmtParams(A1),A0 TST.B fDoVerify(A0) ;should we verify the track also? BEQ.S @FTNoVfy ;-> nawÉ BSR.S gVerCopy ;go verify that the format's OK BNE.S @FTExit ;-> it's not MOVEA.L fmtParams(A1),A0 ;get the format parameters pointer @FTNoVfy MOVEQ #0,D1 MOVE.W SectCnt(A1),D1 ; adjust data and tag buffer pointers LSL.L #2,D1 MOVE.L D1,D2 ; SectCnt*4 ADD.L D1,D1 ADD.L D1,D2 ; SectCnt*12 LSL.L #6,D1 ; SectCnt*512 ADD.L D1,(A0)+ ;advance the user data buffer pointer ADD.L D2,(A0)+ ; and the tag data buffer pointer BSET #3,SideTrack(A1) ; are we on the second side already? BNE.S @FTSide2 ; br if so TST.B TwoSided(A1) ; format two-sides? BNE gFmtCopyTrk ; br if so and format the other side @FTSide2 MOVEQ #0,D0 ; success! @FTExit TST.W D0 RTS @DecrSync ADDQ.W #1,D2 ; if only one, don't worry BEQ.S @FTExitOK @DecrSn1 SUBQ.W #1,(A0) ; decrement GapSync CMP.W #minSync,(A0) ; not below the minimum tho BLT.S @FTExit BRA.S @FmtTrk1 ; otherwise, go again ;_______________________________________________________________________________ ; ; Routine: gVerCopy ; ; Inputs: A1 -- pointer to SonyVars ; D1 -- offset to drive's vars ; SideTrack -- current side and track number ; ; Outputs: D0 -- result code ; ; Function: Verifies that all sectors (current side) have been written correctly. ;_______________________________________________________________________________ gSectorSave EQU gapSync+2 gSectorMap EQU gSectorSave+2 gSectorCnt EQU gSectorMap+2 gVerCopy ORI #HiIntMask,SR ; no interrupts LEA gSectorMap(A1),A0 MOVEQ #0,D0 MOVE.B SideTrack+1(A1),D0 ;get the current track LSR.W #4,D0 ; and convert it to a zone number MOVE.W #$0FFF,D2 ;calculate the bitmap for this track LSR.W D0,D2 MOVE.W D2,(A0)+ MOVEQ #12,D2 SUB D0,D2 ; sectors this track LSL.W #2,D2 ; allow some slop (may not get 1-1) MOVE.W D2,(A0) @VTLoop BSR RdAddrSetup ; get next address mark BMI.S @1 ; br if error MOVE.W D2,gSectorSave(A1) ; save sector number CMP.W SideTrack(A1),D1 ;Do the track and side also match our expectations? BNE.S @1 ;-> no, something's a tad wrong, me thinks MOVEA.L fmtParams(A1),A0 ;get our format parameters MOVEA.L (A0),A0 ; and point to the base buffer address for this track MOVEQ #9,D0 LSL.W D0,D2 ADDA.W D2,A0 ;point to where this sector's data should be ST DskVerify ; make sure we're verifying BSR RdData ; verify a sector BMI.S @1 ; -> verify error BSR GetDrv1 LEA gSectorSave(A1),A0 MOVE.W (A0)+,D2 ; sector we just read MOVE.W (A0),D3 ; sector map BCLR D2,D3 ; mark this sector gotten MOVE.W D3,(A0) ; stash bitmap back @1 BSR.S toEmptyPD ; get rid of data LEA gSectorMap(A1),A0 TST.W (A0)+ ; have we read all the sectors? BEQ.S @VTExitOK ; -> yes, all done SUBQ.W #1,(A0) ; decrement sector count BNE.S @VTLoop ; loop until done MOVEQ #VerErr,D0 ; should get 1-1 ok reads BRA.S @VTExit @VTExitOK MOVEQ #0,D0 @VTExit ANDI #$F8FF,SR TST.W D0 RTS eject ;_____________________________________________________________________ ; ; Routine: gDoFmtCopy ; ; Inputs: none ; ; Outputs: D0 -- result code (0 if format ok) ; ; Function: Formats the current track; the disk is assumed to be up ; to speed and correctly positioned, and interrupts disabled. ; ; write 200 sync groups (get something on the disk) ; start with sector 0: do 2-1 soft interleave ; ; loop: intersector gap sync groups ; 10 $A9 nybbles (only before sector 0) ; 1 sync group (6) ; D5 AA 96 trk sec side vol cksum DE AA FF (11) ; 1 sync group (6) ; D5 AA AD sec (4) ; ; 703 96 nibbles ; DE AA FF ; loop for all sectors ;_____________________________________________________________________ AdjGapSync EQU DskErr ;someplace fast to put the adjusted gap gDoFmtCopy ORI #HiIntMask,SR ; no interrupts MOVEQ #RdDtaAdr,D0 ; PAL address for side 0 MOVE.L SonyVars,A1 BTST #3,SideTrack(A1) ; side 1? BEQ.S @1 ; br if not MOVEQ #RdDta1Adr,D0 ; PAL address for side 1 @1 BSR AdrDisk MOVEA.L IWM,A4 LEA Q6H(A4),A3 ; set up Q6H pointer LEA Q6L(A4),A4 ; set up Q6L pointer MOVE.L DiskBuffer(A1),A5 ; point to nibble buffer LEA DupNibl,A2 ; points to nibble table MOVE.W SectCnt(A1),-(SP) ; number of sectors to write here ;_______________________________________________________________________ ; ; D7 = CkSumC (SP)= sector count ; D6 = CkSumB A6 = pointer to sync group, data mk slip ; D5 = CkSumA A5 = pointer to mark buffer ; D4 = loop counts A4 = ptr to Q6L OR ptr rHandshake (SWIM2)

; D3 = A7A6B7B6C7C6 nibble A3 = ptr to Q6H OR ptr wData (SWIM2)

; D2 = C5C4C3C2C1C0 nibble A2 = ptr to nibble table ; D1 = B5B4B3B2B1B0 nibble A1 = ptr to data buffers ; D0 = A5A4A3A2A1A0 nibble A0 = ptr to user buffer (to A1 after 12) ; ;_______________________________________________________________________ MOVE.W GapSync(A1),D1 ; set up D1 now SUBQ.W #2,D1 ; adjust for DBRA and adr mk sync MOVE.W D1,AdjGapSync MOVEQ #0,D0 ; clear high bytes of D0-D3 now for MOVEQ #0,D1 ; indexing MOVEQ #0,D2 MOVEQ #0,D3 MOVE.W #strtSync-1,D6 TST.B mfmMode(A1) ; are we in ISM mode? BPL.S @NotSWIM2 ; -> no, it's either an IWM or SWIM LEA wData-Q6L(A4),A3 ; point to the write data and LEA rHandshake-Q6L(A4),A4 ; handshake registers for speed MOVE.B #$18,wZeroes-wData(A3) ; clear the write and action bits MOVE.B #$10,wOnes-wData(A3) ; set the write bit MOVE.B #$01,wOnes-wData(A3) ; toggle the clFIFO bit to clear out MOVE.B #$01,wZeroes-wData(A3) ; any data in the FIFO TST.B rError-wData(A3) ; clear the error register again MOVE.B D6,(A3) ; write garbage to FIFO MOVE.B #$08,wOnes-wData(A3); turn on the action bit: GO! bra.s @WrStrtSync ; @NotSWIM2 ; TST.B (A3) ; first byte written is a bit wierd MOVE.B D6,Q7H-Q6H(A3) ; write garbage to start if NonSerializedIO then nop ; force write to complete endif @WrStrtSync LEA SyncTbl,A6 MOVEQ #(syncBytCnt/2)-1,D7 @WSS1 MOVE.B (A6)+,D4 ; prefetch @WrAddrMk1 TST.B (A4) ; check write handshake BPL.S @WrAddrMk1 MOVE.B D4,(A3) ; write out next header nibble if NonSerializedIO then nop ; force write to complete endif MOVE.B (A6)+,D4 ; prefetch @WrAddrMk2 TST.B (A4) ; check write handshake BPL.S @WrAddrMk2 MOVE.B D4,(A3) ; write out next header nibble if NonSerializedIO then nop ; force write to complete endif DBRA D7,@WSS1 DBRA D6,@WrStrtSync @WrNxtSect MOVE.W AdjGapSync,D6 ; number of sync groups - 2 @WrSyncLp LEA SyncTbl,A6 MOVEQ #syncBytCnt-1,D7 @WrSyncByte TST.B (A4) ; check write handshake BPL.S @WrSyncByte MOVE.B (A6)+,(A3) ; write out next gap nibble if NonSerializedIO then nop ; force write to complete endif DBRA D7,@WrSyncByte DBRA D6,@WrSyncLp MOVEQ #adrBytCnt-5,D7 @WrDataMk1 TST.B (A4) ; check write handshake BPL.S @WrDataMk1 MOVE.B (A5)+,(A3) ; write out next data mk nibble if NonSerializedIO then nop ; force write to complete endif DBRA D7,@WrDataMk1 MOVE.B (A5)+,D0 ; prefetch $D5 MOVE.B (A5)+,D3 ; prefetch $AA MOVE.B (A5)+,D1 ; prefetch $AD MOVE.B (A5)+,D2 ; encoded sector number @WrDataMk2 TST.B (A4) ; check write handshake BPL.S @WrDataMk2 MOVE.B D0,(A3) ; write out next data mk nibble if NonSerializedIO then nop ; force write to complete endif ADDQ #1,A5 ; one garbage byte to even it out MOVE.L (A5)+,A1 ; tag data pointer MOVE.L (A5)+,A0 ; data pointer MOVE.L #$2010009,D4 ; adjusted byte write counts for 2 buffers @WrDataMk3 TST.B (A4) ; check write handshake BPL.S @WrDataMk3 MOVE.B D3,(A3) ; write out next adr mk nibble if NonSerializedIO then nop ; force write to complete endif MOVEQ #0,D5 ; zero the initial checksums MOVEQ #0,D6 MOVEQ #0,D7 BRA.S @WrData2 ; D1 has last sync byte, D2 the sector # @WrDataSw MOVE.L A0,A1 ; switch to user buffer @WrData1 ADDX.B D2,D7 ; CSumC'' <- ByteC + CSumC' + ex EOR.B D6,D2 ; ByteC' <- ByteC XOR CSumB' MOVE.B D2,D3 ; D3 = [00][00][00][00][A7][A6][B7][B6] ; [C7][C6][C5][C4][C3][C2][C1][C0] LSR.W #6,D3 ; D3 = [00][00][A7][A6][B7][B6][C7][C6] @WrByteHi1 TST.B (A4) ; check write handshake BPL.S @WrByteHi1 MOVE.B 0(A2,D3.W),(A3) ; nibblize and write hi-bits out if NonSerializedIO then nop ; force write to complete endif SUBQ.W #3,D4 ; got 3 more bytes (wipes out ex bit!) MOVE.B D7,D3 ; D3 <- CSumC ADD.B D7,D3 ; ex <- CSumC[7] ROL.B #1,D7 ; CSumC' <- ROL (CSumC) ; D0 = [xx][xx][A5][A4][A3][A2][A1][A0] @WrByteA1 TST.B (A4) ; check write handshake BPL.S @WrByteA1 MOVE.B 0(A2,D0.W),(A3) ; write low ByteA out if NonSerializedIO then nop ; force write to complete endif @WrData2 MOVE.B (A1)+,D0 ; read next ByteA ADDX.B D0,D5 ; CSumA' <- ByteA + CSumA + ex EOR.B D7,D0 ; ByteA' <- ByteA XOR CSumC' MOVE.B D0,D3 ; D3 = [A7][A6][A5][A4][A3][A2][A1][A0] ROL.W #2,D3 ; D1 = [xx][xx][B5][B4][B3][B2][B1][B0] @WrByteB1 TST.B (A4) ; check write handshake BPL.S @WrByteB1 MOVE.B 0(A2,D1.W),(A3) ; nibblize and write low ByteB out if NonSerializedIO then nop ; force write to complete endif MOVE.B (A1)+,D1 ; read next ByteB ADDX.B D1,D6 ; CSumB' <- ByteB + CSumB + ex EOR.B D5,D1 ; ByteB' <- ByteB XOR CSumA' MOVE.B D1,D3 ROL.W #2,D3 ; D2 = [xx][xx][C5][C4][C3][C2][C1][C0] @WrByteC1 TST.B (A4) ; check write handshake BPL.S @WrByteC1 MOVE.B 0(A2,D2.W),(A3) ; nibblize and write low ByteC out if NonSerializedIO then nop ; force write to complete endif MOVE.B (A1)+,D2 ; read next ByteC TST.W D4 ; reached end of buffer? BNE.S @WrData1 SWAP D4 BNE.S @WrDataSw ; br if we are switching to user buffer ; the last 2 data bytes are written out separately since they are odd . . . ; the missing third byte is just zero . . . @WrLast2 CLR.B D3 ; D3 = [00][00][00][00][A7][A6][B7][B6] ; [00][00][00][00][00][00][00][00] LSR.W #6,D3 ; D3 = [00][00][A7][A6][B7][B6][00][00] @WrByteHi2 TST.B (A4) ; check write handshake BPL.S @WrByteHi2 MOVE.B 0(A2,D3.W),(A3) ; nibblize and write hi-bits out if NonSerializedIO then nop ; force write to complete endif MOVE.B D5,D3 ; start preparing 1st cksum byte ROL.W #2,D3 MOVE.B D6,D3 ROL.W #2,D3 ; D0 = [xx][xx][A5][A4][A3][A2][A1][A0] @WrByteA2 TST.B (A4) ; check write handshake BPL.S @WrByteA2 MOVE.B 0(A2,D0.W),(A3) ; write low ByteA out if NonSerializedIO then nop ; force write to complete endif ; D1 = [xx][xx][B5][B4][B3][B2][B1][B0] @WrByteB2 TST.B (A4) ; check write handshake BPL.S @WrByteB2 MOVE.B 0(A2,D1.W),(A3) ; nibblize and write low ByteB out if NonSerializedIO then nop ; force write to complete endif ; now we write out the three checksum bytes as 4 nibbles @WrCkSum MOVE.B D7,D3 ; D3 = [00][00][00][00][A7][A6][B7][B6] ; [C7][C6][C5][C4][C3][C2][C1][C0] LSR.W #6,D3 ; D3 = [00][00][A7][A6][B7][B6][C7][C6] @WrChkHi TST.B (A4) ; check write handshake BPL.S @WrChkHi MOVE.B 0(A2,D3.W),(A3) ; nibblize and write hi-bits out if NonSerializedIO then nop ; force write to complete endif @WrChkA TST.B (A4) ; check write handshake BPL.S @WrChkA MOVE.B 0(A2,D5.W),(A3) ; write CkSumA out if NonSerializedIO then nop ; force write to complete endif @WrChkB TST.B (A4) ; check write handshake BPL.S @WrChkB MOVE.B 0(A2,D6.W),(A3) ; write CkSumB out if NonSerializedIO then nop ; force write to complete endif @WrChkC TST.B (A4) ; check write handshake BPL.S @WrChkC MOVE.B 0(A2,D7.W),(A3) ; write CkSumC out if NonSerializedIO then nop ; force write to complete endif ; now, finally, write the two bit slip marks and FF byte MOVEQ #3,D7 ADDQ #8,A6 ; point to bit slip marks . . . @WrBitSlip MOVE.B (A4),D1 ; check write handshake BPL.S @WrBitSlip MOVE.B (A6)+,(A3) ; write out next bit slip nibble if NonSerializedIO then nop ; force write to complete endif DBRA D7,@WrBitSlip SUBQ.W #1,(SP) BGT @WrNxtSect ; write all sectors ADDQ #2,SP ; clean up stack . . . MOVEQ #0,D0 ; assume no underrun MOVEA.L SonyVars,A1 ; TST.B mfmMode(A1) ; are we in ISM mode? BPL.S @NotSWIM22 ; -> no, it's either an IWM or SWIM MOVEQ #3-1,D7 ; now write out three more gap bytes to fully clear the FIFO @0 MOVE.B (A4),D1 ; check write handshake BPL.S @0 ; MOVE.B #$FF,(A3) ; write out next gap nibble DBRA D7,@0 ; BTST #5,D1 ; any errors? BEQ.S @WriteOK2 ; branch if no underrun was detected MOVEQ #WrUnderRun,D0 ; underrun error @WriteOK2 MOVE.B #$18,wZeroes-wData(A3) ;Clear the write and action bits MOVE.W D0,Dskerr ; set CCR RTS @NotSWIM22 ; BTST #6,D1 ; test for errors BNE.S @WriteOK ; branch if no underrun was detected MOVEQ #WrUnderRun,D0 ; underrun error @WriteOK TST.B Q7L-Q6L(A4) ; get out of write mode after half TST.B (A4) ; of garbage nibble is written MOVE.W D0,Dskerr ; set CCR RTS ;______________________________________________________________________________ ; ; Routine: FillMarks ; ; Inputs: D6 -- [side (bit 11)][track (bits 10-0)] ; ; Outputs: none (all registers are preserved) ; ; Function: Fills in the buffer with the address marks (buffer is already ; filled with appropriate sync bytes) ; ; 1 sync group (6) ; D5 AA 96 trk sec side vol cksum DE AA FF (11) ; 1 sync group (6) ; D5 AA 0B[->AD] sec 00 (5) ; tag buffer pointer (4) ; data buffer pointer (4) ; ;______________________________________________________________________________ FillMarks MOVEM.L A0-A4/D0-D7,-(SP) MOVEA.L DiskBuffer(A1),A0 ;stack buffer MOVEA.L fmtParams(A1),A2 MOVEA.L (A2)+,A4 ; get the user data buffer pointer MOVE.L (A2)+,A3 ; get the tag buffer pointer MOVEQ #0,D3 MOVE.B (A2),D3 ; get format byte MOVEQ #12,D0 ; max number of sectors/track MOVEQ #$7F,D2 ; isolate the track AND.W D6,D2 ; copy side/track LSR.W #4,D2 ; divide by 16 to get speed group SUB.W D2,D0 ; number of sectors on this track MOVE.W D0,SectCnt(A1) ; save for later LEA DupNibl,A1 ; nibble code table LEA TwoToOne,A2 ; point to 2-1 interleave table MOVE.B 0(A1,D3),D7 ; D7 holds encoded volume byte MOVE.B D3,D5 ; start checksum ANDI.B #$0F,D3 ; isolate bits 3-0 SUBQ.B #2,D3 ; if = 2, then 2-1 interleave BEQ.S @0 LEA FourToOne,A2 ; use 4-1 table instead... @0 MULU #12,D2 ; multiply by 12 to index into table ADD.W D2,A2 ; bump table pointer to correct entry MOVEQ #$3F,D3 ; 6-bit mask AND.B D6,D3 ; get track low 6 bits MOVE.B 0(A1,D3),D2 ; D2 holds encoded track number EOR.B D3,D5 ; add it to checksum LSR.W #6,D6 ; get track high bits/side EOR.B D6,D5 ; add it to checksum MOVE.B 0(A1,D6),D6 ; D6 holds encoded side/trk @1 SWAP D0 ; D0=[max sectors][current sector] MOVEQ #0,D1 MOVE.B 0(A2,D0),D1 ; get next sector number from table MOVE.B 0(A1,D1),D3 ; D1 = next sector number, d3 = encoded MOVEQ #0,D4 ; clear high bytes MOVE.B D5,D4 ; checksum minus sector nibble EOR.B D1,D4 ; add it in ADDA.W #TrkOffset,A0 ; bump to track MOVE.B D2,(A0)+ ; encoded track MOVE.B D3,(A0)+ ; encoded sector MOVE.B D6,(A0)+ ; encoded side MOVE.B D7,(A0)+ ; encoded volume MOVE.B 0(A1,D4),(A0)+ ; checksum ADDA.W #11,A0 ; point to data mark $AD MOVE.B #11,(A0)+ ;this must be "unencoded" (11->$AD) MOVE.B D1,(A0)+ ; unencoded sector number CLR.B (A0)+ ; unused byte MOVE.L D1,D4 ; sector number ADD.W D4,D4 ADD.W D1,D4 LSL.W #2,D4 ; sector number*12 ADD.L A3,D4 ; appropriate tags MOVE.L D4,(A0)+ ; tag buffer pointer MOVEQ #9,D4 LSL.W D4,D1 ; sector number*512 ADD.L A4,D1 ; appropriate data MOVE.L D1,(A0)+ ; data buffer pointer ADDQ.W #1,D0 ; count a sector MOVE.W D0,D1 SWAP D0 CMP.W D0,D1 ; at max? BLT.S @1 ; -> no, next sector MOVEM.L (SP)+,A0-A4/D0-D7 RTS ;______________________________________________________________________________ ; ; Routine: mFmtCopyTrk ; ; Inputs: SideTrack contains the current track and side ; ; Outputs: D0 -- result code ; ; Function: Formats the current track by writing the address header and data ; block for all sectors on both sides. ;______________________________________________________________________________ mFmtCopyTrk BSR GetDrv1 MOVE.W SideTrack(A1),D4 ;Current side/track MOVEQ #0,D5 ;Assume side 0 BCLR #11,D4 ;Is it? BEQ.S @1 MOVEQ #1,D5 ;No, it's side 1 MOVEQ #0,D2 ; <2.1> MOVE.W TimeDBRA,D2 ;wait 750usec before switching heads or <2.1> MOVE.L D2,D0 ; the drive will ignore us, and then <2.1> ADD.L D2,D0 ; where will we be? <2.1> ADD.L D2,D0 ; <2.1> LSR.L #2,D0 ; <2.1> @0 DBRA D0,@0 ;just sit here for a bit... <2.1> @1 MOVEQ #9-1,D2 ;Assume 1 meg format MOVE.B twoMegFmt(A1,D1),D0 ;Is this a double-density disk? BPL.S @2 MOVEQ #18-1,D2 ;Yes, there are twice as many sectors BSET #31,D2 ;Mark as double-density @2 BSR mDoFmtCopy ;Format the track (disables interrupts) MOVEA.L fmtParams(A1),A1 MOVEA.L (A1),A2 ;get the base buffer pointer for this track side MOVE.L A0,(A1) ; and update it for next time BSR toEmptyPD ;Get rid of poll data (saves D0 in DskErr) ANDI #$F8FF,SR ;Open up interrupts MOVE.W DskErr,D0 ;Was there an error? BNE.S @4 ;-> yes, return immediately MOVEA.L fmtParams(A1),A0 TST.B fDoVerify(A0) ;should we verify the track also? BEQ.S @3 ;-> nawÉ BSR.S mVerCopy ;now go verify the format's OK BNE.S @4 ;-> error so exit immediately BSR GetDrv1 ;Point to drive vars @3 BSET #3,SideTrack(A1) ;Is this the second side? BEQ.S mFmtCopyTrk ;-> no, go format it now MOVEQ #0,D0 ;Format was successful @4 RTS ;_______________________________________________________________________________ ; ; Routine: mVerCopy ; ; Inputs: A1 -- pointer to SonyVars ; A2 -- pointer to base buffer address for this track side ; D1 -- offset to drive's vars ; SideTrack -- current side and track number ; ; Outputs: D0 -- result code ; ; Function: Verifies that all sectors (current side) have been written correctly. ;_______________________________________________________________________________ mVerCopy MOVEM.L D2-D7,-(SP) ORI #HiIntMask,SR ;Turn off interrupts @1 MOVEQ #2*9,D7 ;Assume 1 meg format (double sector count) MOVE.L #$000003FE,D6 ;Sector map (1-9) BSR GetDrv1 TST.B twoMegFmt(A1,D1) ;Is this a double-density disk? BPL.S @2 MOVEQ #2*18,D7 ;Yes, twice as many sectors MOVE.L #$0007FFFE,D6 ; and a bigger sector map (1-18) @2 BSR RdAddrSetup ;Get the next address mark BNE.S @3 ;-> error BTST D2,D6 ;Have we already read this sector? BEQ.S @3 ;-> yes, skip CMP.W SideTrack(A1),D1 ;Do the track and side also match our expectations? BNE.S @3 ;-> no, something's a tad wrong, me thinks MOVE.W D2,D3 ;Save the sector number SUBQ.W #1,D2 ;calculate the buffer offset for this sector MOVEQ #9,D0 LSL.L D0,D2 ADD.L DiskBuffer(A1),D2 MOVEA.L D2,A0 ST DskVerify ;make sure we're verifying BSR mRdData ;Verify the sector BNE.S @3 ;-> error BCLR D3,D6 ;Mark the sector as read @3 BSR toEmptyPD ;Get rid of poll data (saves D0 in DskErr) TST.L D6 ;Have all the sectors been read? DBEQ D7,@2 ;Keep looping if not BEQ.S @4 MOVEQ #VerErr,D0 ;Return an error 'cause we couldn't @4 ANDI #$F8FF,SR ;Open up interrupts MOVEM.L (SP)+,D2-D7 TST.W D0 RTS ;_______________________________________________________________________________ ; ; Routine: mDoFmtCopy ; ; Inputs: D2 -- sectors/track - 1 (8 or 17); if 17, bit 31 will be set=1 ; D4 -- track ; D5 -- side ; ; Outputs: A1 -- updated user data buffer pointer ; D0 -- result code ; ; Uses: A3 -- pointer to Write Data register ; A4 -- pointer to Handshake register ; A5 -- pointer to 6522 A-reg (has wait/req) ; A6 -- pointer to SCC A-channel data register ; D0 -- loop counter ; D1 -- byte to write ; D3 -- loop counter ; D6 -- sector ; ; Function: Formats the current track; the disk is assumed to be up to ; speed and correctly positioned, and interrupts disabled. ; ; ; write some gap bytes while waiting for the rising edge of index ; ; Gap bytes ($4E) [ 32] ; ; starting with sector 1: ; loop: Sync bytes ($00) [ 12] ; A1 A1 A1 FE cyl side sect size CRC [ 10] ; Gap bytes ($4E) [ 22] ; Sync bytes ($00) [ 12] ; A1 A1 A1 FB data bytes CRC [518] ; Gap bytes ($4E) [ 80 for 720K, 108 for 1440K] ; loop for all sectors ; ; write gap bytes until the rising edge of index is sensed ;_______________________________________________________________________________ mDoFmtCopy MOVE.L (SP)+,DskRtnAdr ;Save return address MOVEQ #RdDtaAdr,D0 ;PAL address for side 0 TST.W D5 ;Side 0? BEQ.S @1 ;-> yes MOVEQ #RdDta1Adr,D0 ;PAL address for side 1 @1 BSR AdrDisk ;Select head MOVEQ #4,D0 BSR SetUpPoll ;Set up A5, A6, PollStack MOVEA.L fmtParams(A1),A0 ;pointer to the user data buffer MOVEA.L (A0),A0 MOVE.L A0,DiskBuffer(A1) ;save it for later MOVEA.L IWM,A4 LEA wData(A4),A3 ;Point to the write data and LEA rHandshake(A4),A4 ;handshake registers for speed TST.B rError-wData(A3) ;Clear the error register MOVE.B #$18,wZeroes-wData(A3) ;Clear the write and action bits MOVE.B #$10,wOnes-wData(A3) ;Set the write bit MOVE.B #$01,wOnes-wData(A3) ;Toggle the clFIFO bit to clear out MOVE.B #$01,wZeroes-wData(A3) ; any data in the FIFO TST.B rError-wData(A3) ; clear the error register again ; Write a bunch of gap bytes while waiting for the start of index. We track index ; by waiting for it to go low (if it starts high), then go high (start of index). MOVEQ #gapByte,D1 MOVE.B D1,(A3) ;Write the first two gap bytes MOVE.B D1,(A3) ; to fill up the FIFO MOVE.B #$08,wOnes-wData(A3);Turn on the action bit: GO! if NonSerializedIO then nop ; force write to complete endif MOVE.W #2*6750,D3 ;Assumes 300 rpm disk (with variation), 16uSec/byte @WtIndexLo _PollSCC ; poll the SCC modem port
@WtIndexLo1 MOVE.B (A4),D0 ;Wait until there's an opening in the FIFO BPL.S @WtIndexLo1 MOVE.B D1,(A3) ;Write a gap byte if NonSerializedIO then nop ; force write to complete endif BTST #3,D0 ;Is index pulse low? BEQ.S @WtIndexHi ;-> yes, now go wait for it to go high DBRA D3,@WtIndexLo BRA @NoFmtIndex ;-> timed out waiting for index @WtIndexHi _PollSCC ; poll the SCC modem port
@WtIndexHi1 MOVE.B (A4),D0 ;Wait until there's an opening in the FIFO BPL.S @WtIndexHi1 MOVE.B D1,(A3) ;Write a gap byte if NonSerializedIO then nop ; force write to complete endif BTST #3,D0 ;Is index pulse high? BNE.S @FmtStart ;-> yes, start the actual format DBRA D3,@WtIndexHi BRA @NoFmtIndex ;-> timed out waiting for index ; When we get here, we're just after the rising edge of the index pulse. ; First thing we write on the track is a starting gap and sync bytes... @FmtStart MOVE.B #$F5,wPhase-wData(A3) ;turn off the index signal while we format if NonSerializedIO then nop ; force write to complete endif MOVEQ #gap4aSize-1-1,D0 @FmtGap4a _PollSCC ; poll the SCC modem port
@FmtGap4aHS TST.B (A4) ;Wait until there's an opening in the FIFO BPL.S @FmtGap4aHS MOVE.B D1,(A3) ;Write out a gap byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtGap4a MOVEQ #syncSize-1,D0 MOVEQ #theSync,D1 @FmtIdxSync _PollSCC ; poll the SCC modem port
@FmtIdxSnHS TST.B (A4) ;Wait until there's an opening in the FIFO BPL.S @FmtIdxSnHS MOVE.B D1,(A3) ;Write out a sync byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtIdxSync ; Now write the index mark ($C2 $C2 $C2 $FC)... MOVEQ #markSize-1-1,D0 @WrIndexMk _PollSCC ; poll the SCC modem port
@WrIndxMkHS TST.B (A4) ;Wait until there's an opening in the FIFO BPL.S @WrIndxMkHS MOVE.B #$C2,wMark-wData(A3);Write out an index mark byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@WrIndexMk @WrIndxMkFC TST.B (A4) ;Wait until there's an opening in the FIFO BPL.S @WrIndxMkFC MOVE.B #$FC,(A3) ;Write out the last mark byte if NonSerializedIO then nop ; force write to complete endif ; Write another gap... MOVEQ #gap1Size-1,D0 @FmtGap1 _PollSCC ; poll the SCC modem port
@FmtGap1HS TST.B (A4) ;Wait until there's an opening in the FIFO BPL.S @FmtGap1HS MOVE.B #gapByte,(A3) ;Write out a gap byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtGap1 MOVEQ #1,D6 ;Starting sector number BRA.S @FmtAdrSync ;Start a sector with the address mark sync ; Tack yet another gap onto the end of the sector... @FmtNxtSect MOVEQ #gap3Sz720K-1,D0 TST.L D2 ;Is it the 1440K format? BPL.S @FmtGap3 MOVEQ #gap3Sz1440K-1,D0 ;Yes, there's a larger inter-sector gap @FmtGap3 _PollSCC ; poll the SCC modem port
@FmtGap3HS TST.B (A4) BPL.S @FmtGap3HS MOVE.B #gapByte,(A3) ;Write out a gap byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtGap3 ; For each sector -- write sync bytes... @FmtAdrSync MOVEQ #syncSize-1,D0 MOVEQ #theSync,D1 @FmtASyncLp _PollSCC ; poll the SCC modem port
@FmtASyncHS TST.B (A4) ;Wait until there's an opening in the FIFO BPL.S @FmtASyncHS MOVE.B D1,(A3) ;Write out a sync byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtASyncLp ; Write the address mark and field... MOVEQ #markSize-1-1,D0 @FmtAdrMark _PollSCC ; poll the SCC modem port
@FmtAdrMkHS TST.B (A4) BPL.S @FmtAdrMkHS MOVE.B #$A1,wMark-wData(A3);Write out a mark byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtAdrMark @FmtAdrMkFE TST.B (A4) BPL.S @FmtAdrMkFE MOVE.B #$FE,(A3) ;Write out the last mark byte if NonSerializedIO then nop ; force write to complete endif _PollSCC ; poll the SCC modem port
@FmtAdrTrk TST.B (A4) BPL.S @FmtAdrTrk MOVE.B D4,(A3) ;Write the track number if NonSerializedIO then nop ; force write to complete endif _PollSCC ; poll the SCC modem port
@FmtAdrSide TST.B (A4) BPL.S @FmtAdrSide MOVE.B D5,(A3) ;Write the side number if NonSerializedIO then nop ; force write to complete endif _PollSCC ; poll the SCC modem port
@FmtAdrSect TST.B (A4) BPL.S @FmtAdrSect MOVE.B D6,(A3) ;Write the sector number if NonSerializedIO then nop ; force write to complete endif _PollSCC ; poll the SCC modem port
@FmtAdrBlkS TST.B (A4) BPL.S @FmtAdrBlkS MOVE.B #$02,(A3) ;Write the blocksize ($02=512 bytes/block) if NonSerializedIO then nop ; force write to complete endif ; End the address field with 2 CRC bytes... _PollSCC ; poll the SCC modem port
@FmtAddrCRC TST.B (A4) BPL.S @FmtAddrCRC MOVE.B D0,wCRC-wData(A3) ;"Write" CRC bytes if NonSerializedIO then nop ; force write to complete endif ; Write the intra-sector gap and sync bytes... MOVEQ #gap2Size-1,D0 @FmtGap2 _PollSCC ; poll the SCC modem port
@FmtGap2HS TST.B (A4) BPL.S @FmtGap2HS MOVE.B #gapByte,(A3) ;Write out a gap byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtGap2 MOVEQ #syncSize-1,D0 MOVEQ #theSync,D1 @FmtDtaSync _PollSCC ; poll the SCC modem port
@FmtDSyncHS TST.B (A4) BPL.S @FmtDSyncHS MOVE.B D1,(A3) ;Write out a sync byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtDtaSync ; Write the data marks... MOVEQ #markSize-1-1,D0 @FmtDtaMark _PollSCC ; poll the SCC modem port
@FmtDtaMkHS TST.B (A4) BPL.S @FmtDtaMkHS MOVE.B #$A1,wMark-wData(A3);Write out a mark byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtDtaMark @FmtDtaMkFB TST.B (A4) BPL.S @FmtDtaMkFB MOVE.B #$FB,(A3) ;Write out the last mark byte if NonSerializedIO then nop ; force write to complete endif ; Write the format byte for the sector data... MOVE.W #512-1,D0 @FmtDataBlk _PollSCC ; poll the SCC modem port
@FmtDBlkHS TST.B (A4) BPL.S @FmtDBlkHS MOVE.B (A0)+,(A3) ;Write out a data byte if NonSerializedIO then nop ; force write to complete endif DBRA D0,@FmtDataBlk ; End the sector data with 2 CRC bytes... @FmtDataCRC TST.B (A4) BPL.S @FmtDataCRC MOVE.B D0,wCRC-wData(A3) ;"Write" CRC bytes if NonSerializedIO then nop ; force write to complete endif ADDQ.W #1,D6 ;Next sector DBRA D2,@FmtNxtSect ; Finally, finish off the track with a gap to index to clean things up. ; Five gap bytes will be written before checking for index to make sure ; that the data CRC for the last sector is completely written in case ; it ends up VERY close to the end of the disk (motor speed variation). ; If this is side 0, we'll end the format before the index pulse so that ; we can switch heads in time (about 1ms). This reduces the number of ; revolutions from 4 to 3 per cylinder which saves 16 seconds overall. MOVEQ #5-1,D0 ;We need to write 5 gap bytes so the CRC is shifted out MOVEQ #gapByte,D1 MOVE.W #gap4bSize,D3 TST.W D5 ;is this side 0? <2.1> BNE.S @FmtLastGap ; <2.1> MOVEQ #5-1,D3 ;yes, use the Reader's Digest gap size... <2.1> BRA.S @FmtLastGap @TurnIndxOn MOVE.B #$F4,wPhase-wData(A3) ;turn the index signal back on here if NonSerializedIO then nop ; force write to complete endif ; so there's no glitch in the data @FmtLastGap _PollSCC ; poll the SCC modem port
@FmtLGapHS MOVE.B (A4),D2 ;Wait until there's an opening in the FIFO BPL.S @FmtLGapHS MOVE.B D1,(A3) ;Write a gap byte if NonSerializedIO then nop ; force write to complete endif SUBQ.W #1,D0 ;Have we written enough gap bytes yet? BGT.S @NoChkIndex ;-> nope BEQ.S @TurnIndxOn ;-> turn index back on before we check it BTST #3,D2 ;Is index pulse high? BNE.S @FmtDone ;-> yes, all done <2.1> @NoChkIndex DBRA D3,@FmtLastGap TST.W D5 ;is this side 0? <2.1> BEQ.S @FmtDone ;-> yes, we don't care if we don't see index<2.1> @NoFmtIndex MOVEQ #noIndexErr,D0 ;Timed out waiting for index BRA.S @DoFmtExit ;-> timed out @FmtDone MOVEQ #0,D0 ;Assume no underrun BTST #5,D2 ;Any errors? BEQ.S @DoFmtExit MOVEQ #WrUnderRun,D0 ;Yes, underrun error @DoFmtExit MOVE.B #$18,wZeroes-wData(A3) ;Clear the write and action bits if NonSerializedIO then nop ; force write to complete endif MOVE.L DskRtnAdr,-(SP) TST.W D0 ;Set CCR RTS ; Interleave tables used by FillInMarks to decide which sector interleave to use FourToOne DC.B 0, 3, 6, 9, 1, 4, 7,10, 2, 5, 8,11 ;tracks 0-15 DC.B 0, 3, 6, 9, 1, 4, 7,10, 2, 5, 8, 0 ;tracks 16-31 DC.B 0, 5, 3, 8, 1, 6, 4, 9, 2, 7, 0, 0 ;tracks 32-47 DC.B 0, 7, 5, 3, 1, 8, 6, 4, 2, 0, 0, 0 ;tracks 48-63 DC.B 0, 2, 4, 6, 1, 3, 5, 7, 0, 0, 0, 0 ;tracks 64-79 TwoToOne DC.B 0, 6, 1, 7, 2, 8, 3, 9, 4,10, 5,11 ;tracks 0-15 DC.B 0, 6, 1, 7, 2, 8, 3, 9, 4,10, 5, 0 ;tracks 16-31 DC.B 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, 0, 0 ;tracks 32-47 DC.B 0, 5, 1, 6, 2, 7, 3, 8, 4, 0, 0, 0 ;tracks 48-63 DC.B 0, 4, 1, 5, 2, 6, 3, 7, 0, 0, 0, 0 ;tracks 64-79 ; Nibblizing Table: convert 6 bits into 8-bit code word. ; This table has been specially expanded to 4x the size of the normal table to ; allow the masking operations (zeroing high 2 bits) to be skipped to save time DupNibl DC.B $96,$97,$9A,$9B,$9D,$9E,$9F,$A6,$A7,$AB,$AC,$AD,$AE,$AF,$B2,$B3 DC.B $B4,$B5,$B6,$B7,$B9,$BA,$BB,$BC,$BD,$BE,$BF,$CB,$CD,$CE,$CF,$D3 DC.B $D6,$D7,$D9,$DA,$DB,$DC,$DD,$DE,$DF,$E5,$E6,$E7,$E9,$EA,$EB,$EC DC.B $ED,$EE,$EF,$F2,$F3,$F4,$F5,$F6,$F7,$F9,$FA,$FB,$FC,$FD,$FE,$FF DC.B $96,$97,$9A,$9B,$9D,$9E,$9F,$A6,$A7,$AB,$AC,$AD,$AE,$AF,$B2,$B3 DC.B $B4,$B5,$B6,$B7,$B9,$BA,$BB,$BC,$BD,$BE,$BF,$CB,$CD,$CE,$CF,$D3 DC.B $D6,$D7,$D9,$DA,$DB,$DC,$DD,$DE,$DF,$E5,$E6,$E7,$E9,$EA,$EB,$EC DC.B $ED,$EE,$EF,$F2,$F3,$F4,$F5,$F6,$F7,$F9,$FA,$FB,$FC,$FD,$FE,$FF DC.B $96,$97,$9A,$9B,$9D,$9E,$9F,$A6,$A7,$AB,$AC,$AD,$AE,$AF,$B2,$B3 DC.B $B4,$B5,$B6,$B7,$B9,$BA,$BB,$BC,$BD,$BE,$BF,$CB,$CD,$CE,$CF,$D3 DC.B $D6,$D7,$D9,$DA,$DB,$DC,$DD,$DE,$DF,$E5,$E6,$E7,$E9,$EA,$EB,$EC DC.B $ED,$EE,$EF,$F2,$F3,$F4,$F5,$F6,$F7,$F9,$FA,$FB,$FC,$FD,$FE,$FF DC.B $96,$97,$9A,$9B,$9D,$9E,$9F,$A6,$A7,$AB,$AC,$AD,$AE,$AF,$B2,$B3 DC.B $B4,$B5,$B6,$B7,$B9,$BA,$BB,$BC,$BD,$BE,$BF,$CB,$CD,$CE,$CF,$D3 DC.B $D6,$D7,$D9,$DA,$DB,$DC,$DD,$DE,$DF,$E5,$E6,$E7,$E9,$EA,$EB,$EC DC.B $ED,$EE,$EF,$F2,$F3,$F4,$F5,$F6,$F7,$F9,$FA,$FB,$FC,$FD,$FE,$FF