mac-rom/Drivers/Sony/SonyDup.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

1360 lines
45 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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):
;
; <SM8> 12/14/92 RC Restore Pre-PDM D2 with Horror Roll in
; <SM6> 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.
; <SM5> 12/02/92 HY Added hasPwrControls conditional.
; <SM4> 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 ; <SM5>
TestFor hwCbPwrMgr
BEQ.S @pmgrdone
BSR TurnIWMon ;Turn IWM on with pmgr call
@pmgrdone
ENDIF ; <SM5>
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) <H2><SM5>
; D3 = A7A6B7B6C7C6 nibble A3 = ptr to Q6H OR ptr wData (SWIM2) <H2><SM5>
; 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? <SM5>
BPL.S @NotSWIM2 ; -> no, it's either an IWM or SWIM <SM5>
LEA wData-Q6L(A4),A3 ; point to the write data and <SM5>
LEA rHandshake-Q6L(A4),A4 ; handshake registers for speed <SM5>
MOVE.B #$18,wZeroes-wData(A3) ; clear the write and action bits <SM5>
MOVE.B #$10,wOnes-wData(A3) ; set the write bit <SM5>
MOVE.B #$01,wOnes-wData(A3) ; toggle the clFIFO bit to clear out<SM5>
MOVE.B #$01,wZeroes-wData(A3) ; any data in the FIFO <SM5>
TST.B rError-wData(A3) ; clear the error register again <SM5>
MOVE.B D6,(A3) ; write garbage to FIFO <SM5>
MOVE.B #$08,wOnes-wData(A3); turn on the action bit: GO! <SM5>
bra.s @WrStrtSync ; <SM5>
@NotSWIM2 ; <SM5>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 <SM4>
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 ; <SM6>
TST.B mfmMode(A1) ; are we in ISM mode? <SM6>
BPL.S @NotSWIM22 ; -> no, it's either an IWM or SWIM <SM6>
MOVEQ #3-1,D7 ; now write out three more gap bytes to fully clear the FIFO<SM6>
@0 MOVE.B (A4),D1 ; check write handshake <SM6>
BPL.S @0 ; <SM6>
MOVE.B #$FF,(A3) ; write out next gap nibble <SM6>
DBRA D7,@0 ; <SM6>
BTST #5,D1 ; any errors? <SM6>
BEQ.S @WriteOK2 ; branch if no underrun was detected<SM6>
MOVEQ #WrUnderRun,D0 ; underrun error <SM6>
@WriteOK2 MOVE.B #$18,wZeroes-wData(A3) ;Clear the write and action bits<SM6>
MOVE.W D0,Dskerr ; set CCR <SM6>
RTS
@NotSWIM22 ; <SM6>
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 <SM6>
TST.B rError-wData(A3) ; clear the error register again<SM6>
; 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 <SM4>
endif
MOVE.W #2*6750,D3 ;Assumes 300 rpm disk (with variation), 16uSec/byte
@WtIndexLo _PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4>
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 <H5><SM6>
@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 <SM4>
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 <SM4>
endif
MOVEQ #gap4aSize-1-1,D0
@FmtGap4a _PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4>
endif
DBRA D0,@FmtGap4a
MOVEQ #syncSize-1,D0
MOVEQ #theSync,D1
@FmtIdxSync _PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4>
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 <H5><SM6>
@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 <SM4>
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 <SM4>
endif
; Write another gap...
MOVEQ #gap1Size-1,D0
@FmtGap1 _PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4> <SM4>
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 <H5><SM6>
@FmtGap3HS TST.B (A4)
BPL.S @FmtGap3HS
MOVE.B #gapByte,(A3) ;Write out a gap byte
if NonSerializedIO then
nop ; force write to complete <SM4>
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 <H5><SM6>
@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 <SM4>
endif
DBRA D0,@FmtASyncLp
; Write the address mark and field...
MOVEQ #markSize-1-1,D0
@FmtAdrMark _PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4>
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 <SM4>
endif
_PollSCC ; poll the SCC modem port <H5><SM6>
@FmtAdrTrk TST.B (A4)
BPL.S @FmtAdrTrk
MOVE.B D4,(A3) ;Write the track number
if NonSerializedIO then
nop ; force write to complete <SM4>
endif
_PollSCC ; poll the SCC modem port <H5><SM6>
@FmtAdrSide TST.B (A4)
BPL.S @FmtAdrSide
MOVE.B D5,(A3) ;Write the side number
if NonSerializedIO then
nop ; force write to complete <SM4>
endif
_PollSCC ; poll the SCC modem port <H5><SM6>
@FmtAdrSect TST.B (A4)
BPL.S @FmtAdrSect
MOVE.B D6,(A3) ;Write the sector number
if NonSerializedIO then
nop ; force write to complete <SM4>
endif
_PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4>
endif
; End the address field with 2 CRC bytes...
_PollSCC ; poll the SCC modem port <H5><SM6>
@FmtAddrCRC TST.B (A4)
BPL.S @FmtAddrCRC
MOVE.B D0,wCRC-wData(A3) ;"Write" CRC bytes
if NonSerializedIO then
nop ; force write to complete <SM4>
endif
; Write the intra-sector gap and sync bytes...
MOVEQ #gap2Size-1,D0
@FmtGap2 _PollSCC ; poll the SCC modem port <H5><SM6>
@FmtGap2HS TST.B (A4)
BPL.S @FmtGap2HS
MOVE.B #gapByte,(A3) ;Write out a gap byte
if NonSerializedIO then
nop ; force write to complete <SM4>
endif
DBRA D0,@FmtGap2
MOVEQ #syncSize-1,D0
MOVEQ #theSync,D1
@FmtDtaSync _PollSCC ; poll the SCC modem port <H5><SM6>
@FmtDSyncHS TST.B (A4)
BPL.S @FmtDSyncHS
MOVE.B D1,(A3) ;Write out a sync byte
if NonSerializedIO then
nop ; force write to complete <SM4>
endif
DBRA D0,@FmtDtaSync
; Write the data marks...
MOVEQ #markSize-1-1,D0
@FmtDtaMark _PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4>
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 <SM4>
endif
; Write the format byte for the sector data...
MOVE.W #512-1,D0
@FmtDataBlk _PollSCC ; poll the SCC modem port <H5><SM6>
@FmtDBlkHS TST.B (A4)
BPL.S @FmtDBlkHS
MOVE.B (A0)+,(A3) ;Write out a data byte
if NonSerializedIO then
nop ; force write to complete <SM4>
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 <SM4>
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 <SM4>
endif
; so there's no glitch in the data
@FmtLastGap _PollSCC ; poll the SCC modem port <H5><SM6>
@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 <SM4>
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 <SM4>
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