mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-22 23:29:27 +00:00
4325cdcc78
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.
1360 lines
45 KiB
Plaintext
1360 lines
45 KiB
Plaintext
;
|
||
; 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
|
||
|