sys7.1-doc-wip/Drivers/Sony/SonyMFM.a
2019-07-27 22:37:48 +08:00

2355 lines
86 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: SonyMFM.a
;
; Contains: SWIM/SuperDrive MFM Floppy Disk Support Routines
;
; Written by: Steve Christensen 16-May-86
;
; Copyright: © 1986-1990, 1992 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM10> 1/10/93 RC Added nops for Smurf
; <SM9> 12/14/92 RC Restore Pre-PDM D2 with Horror Roll in
; <SM7> 12/9/92 RC Fixed a build bug which was introduced by the Horror Roll in.
; The bug was in SetChipMode. If nonSerializedIO is TRUE, then
; the nop's will cause one of the BEQ.S to needs to be a BEQ.
; <SM6> 12/8/92 rab Removed a forROM conditional from jtISMRdData that was causing
; an 'Uncompleted conditional directive' warning.
; <SM5> 12/7/92 rab Roll in Horror changes. Comments follow…
; <H11> 9/22/92 DHN Fixed problem in CheckCRC with SWIM2 ASIC where rHandShake bit 8
; (data avail) goes high before its other bits are valid. We read
; rHandShake again to get the valid bits. There are other related
; fixes.
; <H10> 7/21/92 NJV Removed hasSonora1 conditionalized code (no longer needed)
; <H9> 7/15/92 CMP Patched read data mark code to allow for a mark byte in the
; middle of the sync field due to a late write splice. We now
; allow for one bogus mark byte before giving up and returning
; noDMark error.
; <H8> 5/12/92 CMP Patched RdAddrMark. When _PollSCC was called it was messing up
; timing, causing address marks to be missed occaisionally. The
; SCC polling code was put inline to fix this.
; <H6> 3/6/92 CMP Increased mByteTOCnt to 60 to accomodate 33Mhz. CPUs.
; <H4> 11/14/91 SWC Overpatched the SWIM2 code. Patched mAdrDisk to handle HDSEL
; selection using the HDSEL pin on SWIM/SWIM2 in addition to the
; VIA bit so we'll work with DB-Lite's connector bars.
; <SM4> 10/18/92 CCH Added nop's for systems with non-serial writes to IO space.
; <5> 7/14/92 CSS Fixed the comment below so an exact version of this
; file could be copied into SuperMario.
; <4> 4/27/92 JSM Get rid of conditionals: dont use onMacXX style conditionals,
; has3rdFloppyand supportsDCD are always false, forROM is always
; true. Only conditional left is CPU check.
; <3> 7/30/90 BG Removed CPU = 040 conditional in preparation for moving from
; Mac040 to Mac32 build.
; <2> 1/4/90 BG Define preliminary 040-based *reWriteAdj/Mul/Div* values. Also
; added Marks to the file for all routines.
;
; <2.5> 5/26/89 GGD Changed conditional for write gap timing for 020/030 machines.
; <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 Added VIA accesses during mPulse to waste some time to ensure
; adequate pulse width of LSTRB. Added VIA accesses in mDiskSel to
; kill some time.
; <2.0> 12/15/88 GGD Re-wrote write splice timing loop to use TimeVIADB for better
; accuracy. Changed some machine based conditionals to feature
; based.
; <1.2> 11/21/88 CCH Changed ForRam equates to ForRom.
; <1.1> 11/11/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
;
; <1.9> 9/29/88 GGD Changed the gap between sectors for 1440K disks (gap3Sz1440K)
; from 108 to 101 bytes to conform to Sony's latest request to
; improve speed variation margins, and to be compatible with the
; way that IBM is now doing it. Also changed to write splice
; timing computation to use the constant gap2Size instead of the
; hard coded value of 22 (doesn't change the object code).
; <1.8> 9/19/88 GGD SWC/Put the index mark code back into the format routine.
; <1.8> 9/12/88 SWC Put the index mark code back into the format routine. Increased
; the number of read tries in mVerTrack.
; <1.7> 8/16/88 GGD Adjusted write splice timing constants forROM on HcMac (2 wait
; states now) Saved reg D2 in SetChipMode when calling SetIWMMode
; to prevent potential infinate loop, if hardware fails.
; <1.7> 8/11/88 GGD Adjusted write splice timing constants forROM on HcMac (2 wait
; states now) Saved reg D2 in SetChipMode when calling SetIWMMode
; to prevent potential infinate loop, if hardware fails.
; <1.6> 7/15/88 GGD Added extra delays in SetParams to fix violation of SWIM timing
; restriction.
; <1.6> 7/14/88 GGD Added extra delays in SetParams to fix violation of SWIM timing
; restriction.
; <1.5> 6/15/88 GGD No changes to this file, entire Sony Driver is checked out and
; in as a group.
; <1.4> 5/25/88 GGD SWC/Fixed to previous fix in format code, write an extra gap
; btye before turning on Index.
; <1.4> 5/25/88 SWC Fixed to previous fix in format code, write an extra gap btye
; before turning on Index.
; <1.3> 5/24/88 GGD SWC/Turned the index signal off and on in mWrData and mDoFormat
; by selecting mfmDrvAdr/drvModeAdr instead of RdDtaAdr/RdDta1Adr
; so that the index pulse noise problem in the drive will not
; manifest itself anymore.
; <1.3> 5/18/88 SWC Turned the index signal off and on in mWrData and mDoFormat by
; selecting mfmDrvAdr/drvModeAdr instead of RdDtaAdr/RdDta1Adr so
; that the index pulse noise problem in the drive will not
; manifest itself anymore.
; <1.2> 5/3/88 GGD Just checked out and back in to get file version in sync with
; other files in the Sony Driver.
; <1.1> 5/3/88 GGD mWrData: poll the SCC in the initial wait loop. Tuned write
; splice and byte timeout timing constants. Added onNuMacDCD
; support. Made the address mark checking more flexible in
; mRdAddr.
;
; <1.2> 5/2/88 SWC Made the address mark checking more flexible in mRdAddr.
; <1.2> 4/29/88 GGD Added onNuMacDCD support.
; <1.2> 4/28/88 GGD Tuned write splice and byte timeout timing constants.
; <1.2> 4/26/88 SWC mWrData: poll the SCC in the initial wait loop.
; <1.0> 4/18/88 GGD MFM Support <C437> by Steve Christensen
; <1.1> 3/29/88 GGD Removed GCRonMFMErr, since it is now in SysErr.a
; 3/10/88 SWC ChkDiskType: set DiskInPlace(A1,D1) to 3 for 1440K GCR.
; 3/1/88 SWC Updated to latest SWIM params recommended by Sony (their rev
; 4.0).
; 2/23/88 SWC Added GCRonMFMErr equate for 1440K MFM disks formatted as GCR.
; ChkDiskType: return an error if a 1440K MFM disk is formatted as
; GCR.
; 2/22/88 SWC Modified the format code to save a revolution per cylinder
; (saves 16 sec). mVerTrack: changed DataVerErr to VerErr to be
; consistent with GCR verify. mVerTrack: check that the track and
; side numbers are OK as well.
; 2/10/88 SWC ChkDiskType: do a Recal if 2meg to keep chip mode in sync with
; mfmDisk(A1,D1).
; <C437> 2/5/88 SWC Fixed the gap lengths to conform with <ugh> IBM standard.
; <C907> 2/4/88 GGD Port to HcMac (Laguna).
; 2/1/88 SWC Oops! Steve copied the SE internal drive switch bug from
; DiskSelect into mDiskSelect, but now it's fixed.
; 1/25/88 SWC Compacted the read-mark-byte loops in mRdAddr and mRdData. New
; parameters! (more to come, no doubt).
; 1/20/88 SWC CRC error -OR- error register bit set -> flag as CRC error.
; 1/11/88 SWC Increased SE timeout counter value (we were timing out when the
; code was put into ROM). Always set error correction OFF (noisy
; environments were messing up its performance).
; 12/22/87 SWC Fixed SetChipMode so we always exit in a non-write state if the
; IWM register set is selected.
; 12/8/87 SWC Move parameter RAM setup to SetParams so we can use various
; parameter sets for different portions of the disk. Always set
; error correction ON for address fields (mRdAddr) and OFF for
; data fields (mRdData).
; 12/4/87 SWC Added a second access of the error register to make sure the
; chip wasn't staying in a weird state for R/W operations. Tied
; the re-write delay into TimeDBRA so we're relatively independent
; of processor speed.
; 11/23/87 SWC Clear SideTrack(A1) in GetASector (ChkDiskType) so that we will
; read off of side 0 (in case it's a 400K disk).
; 11/5/87 SWC Turned off error correction as the default setting.
; 9/30/87 SWC Fixed the sector re-write gap time in mWrData.
; 9/3/87 SWC Changed mDoFormat slightly to handle greater drive speed
; variation.
; 8/18/87 SWC Changed the IWM->ISM switch to the new "magic sequence".
; 7/9/87 SWC Added delays (SCC checks) to mDoFormat to increase the time
; between successive chip accesses when running on a Mac II.
; 4/16/87 SWC Converted ICBM routines to work with SWIM. Added mAdrDisk,
; mSense, mPulse, mDiskSelect to handle disk command/status when
; the MFM register set is selected.
; <C437> 2/25/87 SWC Added these routines to Sony driver to support MFM disks.
title 'File: SonyMFM.a'
;______________________________________________________________________________
;
; SWIM/SuperDrive MFM Floppy Disk Support Routines
;
; This file contains all routines necessary to support MFM disks using the
; SWIM disk controller and Sony MFM/GCR drives. The rest of the Sony driver
; has been modified where necessary so that it knows about MFM. In general,
; the MFM routines that have GCR counterparts look the same to the outside
; world.
;
; Routines:
;
; Check4SWIM -- Checks for the presence of a SWIM, and if one is found,
; initializes it and the appropriate Sony vars.
; SetChipMode -- selects the appropriate register set (IWM/SWIM) for the
; current disk.
; SetParams -- stuffs a set of 16 values into the SWIM's parameter RAM
; based on the current track.
; ChkDiskType -- finds out whether an MFM or GCR disk is inserted.
; mAdrDisk -- selects a drive address without reading or writing.
; mSense -- reads the state of the currently-selected drive address.
; mPulse -- strobes the LSTRB (phase 3) line to execute a drive command.
; mDiskSelect -- finishes disk selection if the SWIM register set is selected.
; mGetTrack -- given the block number, calculate the track, head, sector.
; mRdAddr -- Returns information about the next address mark to spin by.
; mRdData -- Reads the contents of a sector into the user's buffer.
; mWrData -- Writes the contents of the user's buffer into a sector.
; mFmtTrack -- Formats both sides of the current track
; mDoFormat -- Formats one side of the current track.
; mVerTrack -- Verifies both sides of the current track.
;______________________________________________________________________________
BLANKS ON
STRING ASIS
;______________________________________________________________________________
;
; MFM Read/Write/Format constants used only in this file
;______________________________________________________________________________
;Field sizes:
gap4aSize EQU 80 ;Gap between index and index mark <1.8>
gap1Size EQU 50 ;Gap between index mark and sector 1 <1.8>
gap2Size EQU 22 ;Gap between address and data fields
gap3Sz720K EQU 80 ;Gap between adjacent sectors (720K)
gap3Sz1440K EQU 101 ;Gap between adjacent sectors (1440K) <1.9>
gap4bSize EQU 1000 ;Gap from end of last sector to index (max) <1.8>
syncSize EQU 12 ;Sync field size
markSize EQU 4 ;Size of index/address/data marks
gapByte EQU $4E ;Inter/intra sector gap byte
theSync EQU $00 ;Sync byte preceeding each mark
fmtFillByte EQU $F6-256 ;Format byte to fill sectors with
noIndexErr EQU Fmt2Err ;Use this one to show index timeout
dataTOErr EQU noNybErr ;Timed out while waiting to read a byte
mByteTOCnt EQU 60 ; byte timeout count (for reading) <H6><SM5>
mSctrTOCnt EQU 20000 ;"Look for Address Mark" timeout count
reWriteAdj EQU (71+60)/2 ; uSecs already used from 22 byte write gap time <2.0>
reWriteMul EQU 20 ; number of clocks in ROM TimeVIADB loop <2.0>
reWriteDiv EQU 20 ; number of clocks in RAM TimeVIADB loop <2.0>
;______________________________________________________________________________
;
; The format of an MFM track is as follows:
;
; Index Pulse->
; [ 80] gap bytes $4E
; [ 12] sync field $00
; [ 4] index mark $C2,$C2,$C2,$FC
; [ 50] gap $4E
; LOOP:
; [ 12] sync field $00 <-------------------+
; [ 4] address mark $A1,$A1,$A1,$FE <-------+ |
; [ 1] cylinder number $00 to $4F | |
; [ 1] side number $00 to $01 address field |
; [ 1] sector number $01 to $09/$12 | |
; [ 1] format byte $02=512 bytes/sector | |
; [ 2] CRC $0000 to $FFFF <-------+ 1 sector
; [ 22] inter-sector gap $4E |
; [ 12] sync field $00 |
; [ 4] data mark $A1,$A1,$A1,$FB <-------+ |
; [512] sector data $00 to $FF data field |
; [ 2] CRC $0000 to $FFFF <-------+ |
; [ 80] gap (101 for 1440K) $4E <-------------------+
; REPEAT FOR 8 or 17 MORE SECTORS
; [xxx] gap to index $4E
; Index Pulse->
;______________________________________________________________________________
;______________________________________________________________________________
;
; Routine: Check4SWIM
;
; Inputs: none
;
; Outputs: A1 -- pointer to SonyVars
;
; A0,D0 are trashed
;
; Function: Checks for the presence of a SWIM, and if one is found, sets isSWIM(A1).
;______________________________________________________________________________
Check4SWIM MOVEA.L SonyVars,A1
MOVE SR,-(SP) ;Save SR
ORI #HiIntMask,SR ;and disable interrupts
MOVEA.L IWM,A0
TST.B IntDrive(A0) ;Be sure the internal drive is selected
TST.B Q7L(A0) ;Select the mode register
TST.B MtrOff(A0)
TST.B Q6H(A0)
MOVEQ #$40++IWMMode,D0
MOVE.B D0,Q7H(A0) ;Try to put the chip into MFM mode
MOVE.B #IWMMode,Q7H(A0) ;The "magic sequence" is to set bit 6
MOVE.B D0,Q7H(A0) ; to "1", "0", "1", "1" over four
MOVE.B D0,Q7H(A0) ; consecutive accesses
MOVEQ #$F5-256,D0 ;If we can write to the phase register
MOVE.B D0,wPhase(A0) ;and read back the same value, this
if NonSerializedIO then
nop ; force write to complete force write to complete <SM4>
endif
CMP.B rPhase(A0),D0 ;must be an SWIM
BNE.S @1 ;-> mismatch: IWM
MOVEQ #$F6-256,D0
MOVE.B D0,wPhase(A0)
if NonSerializedIO then
nop ; force write to complete
endif
CMP.B rPhase(A0),D0
BNE.S @1 ;-> mismatch: IWM
MOVEQ #$F7-256,D0
MOVE.B D0,wPhase(A0)
if NonSerializedIO then
nop ; force write to complete
endif
CMP.B rPhase(A0),D0
BNE.S @1 ;-> mismatch: IWM
ST isSWIM(A1) ;A SWIM is installed
MOVE.B #$F8,wZeroes(A0) ;Switch back to IWM register set
if NonSerializedIO then
nop ; force write to complete
endif
@1 TST.B Q7L(A0) ;Back to read state with the drive enabled
TST.B Q6L(A0)
TST.B MtrOn(A0)
TST.B isSWIM(A1) ; do we have at least a SWIM <SM5>
BPL.S @2 ; -> no, done <SM5>
MOVEQ #$F5-256,D0 ; if we can write to the phase register <SM5>
MOVE.B D0,wPhase(A0) ; and read back the same value, this <SM5>
if NonSerializedIO then
nop ; force write to complete <SM5>
endif
CMP.B rPhase(A0),D0 ; must be an SWIM2 <SM5>
BNE.S @2 ; -> mismatch: SWIM <SM5>
MOVEQ #$F6-256,D0 ; <SM5>
MOVE.B D0,wPhase(A0) ; <SM5>
if NonSerializedIO then
nop ; force write to complete <SM5>
endif
CMP.B rPhase(A0),D0 ; <SM5>
BNE.S @2 ; -> mismatch: SWIM <SM5>
MOVEQ #$F7-256,D0 ; <SM5>
MOVE.B D0,wPhase(A0) ; <SM5>
if NonSerializedIO then
nop ; force write to complete <SM5>
endif
CMP.B rPhase(A0),D0 ; <SM5>
BNE.S @2 ; -> mismatch: SWIM <SM5>
SUBQ.B #1,isSWIM(A1) ; a SWIM2 is installed <SM5>
ST mfmMode(A1) ; make sure we always use the ISM register set <SM5>
LEA jtISMRdAddr,A0 ; use special SWIM2 routines for GCR reading <SM5>
MOVE.L A0,JRdAddr ; <SM5>
LEA jtISMRdData,A0 ; <SM5>
MOVE.L A0,JRdData ; <SM5>
BSR CheckFor32Mhz ; check for high speed clock to SWIM2 <H9><SM5>
@2 MOVE (SP)+,SR ;Enable interrupts
RTS
;______________________________________________________________________________
;
; Routine: SetChipMode
;
; Inputs: none
;
; Outputs: D0 -- result code
;
; Function: Selects the appropriate register set for the current disk.
;______________________________________________________________________________
;
; If we can write to the SWIM phase register and read back the same values,
; we must be in SWIM mode. The three phase combinations used are safe for
; use even if an HD-20 is selected since they are the ID states...
SetChipMode BSR GetDrv1 ;Setup A1,D1
TST.B isSWIM(A1) ;Is a SWIM connected?
BPL SetIWMMode ;-> if not, just init IWM style
MOVE SR,-(SP) ; save SR <SM5>
ORI #HiIntMask,SR ; and disable interrupts <SM5>
MOVEA.L IWM,A0 ; <SM5>
CMP.B #-2,isSWIM(A1) ; see if this is a SWIM2 <SM5>
BEQ @2 ; <SM5>
MOVEQ #2-1,D2 ;Retry count for setting MFM mode
@0 MOVEA.L IWM,A0
MOVE.B #$38,wZeroes(A0) ;Turn off ACTION in case we're in ISM mode
if NonSerializedIO then
nop ; force write to complete <SM5>
endif
MOVEQ #$F5-256,D0
MOVE.B D0,wPhase(A0)
if NonSerializedIO then
nop ; force write to complete
endif
CMP.B rPhase(A0),D0
BNE.S @1 ;-> mismatch: IWM register set
MOVEQ #$F6-256,D0
MOVE.B D0,wPhase(A0)
if NonSerializedIO then
nop ; force write to complete
endif
CMP.B rPhase(A0),D0
BNE.S @1 ;-> mismatch: IWM register set
MOVEQ #$F7-256,D0
MOVE.B D0,wPhase(A0)
if NonSerializedIO then
nop ; force write to complete
endif
CMP.B rPhase(A0),D0
BNE.S @1 ;-> mismatch: IWM register set
; If we get to this point, the SWIM register set is currently selected...
TST.B mfmDisk(A1,D1) ;Do we want to be in MFM mode?
BMI.S @2 ;-> yes, go finish the initialization
MOVE.B #$F8,wZeroes(A0) ;else switch back to the IWM register set
if NonSerializedIO then
nop ; force write to complete
endif
TST.B Q7L(A0) ;and get out of write mode
; ...and here the IWM register set is selected...
@1 CLR.B mfmMode(A1) ;We're in IWM mode
MOVE.L D2,-(SP) ; preserve D2 (SetIWMMode uses it) <1.7>
BSR SetIWMMode ; so go do a normal initialization
MOVE.L (SP)+,D2 ; restore D2 <1.7>
TST.W D0 ; re-check the error code <1.7>
BNE.S @6 ;-> couldn't initialize the chip
TST.B mfmDisk(A1,D1) ;Is IWM mode where we want to be?
BPL.S @6 ;Yes, all done
TST.B Q7L(A0) ;Select the mode register
TST.B MtrOff(A0)
TST.B Q6H(A0)
MOVEQ #$40++IWMMode,D0
MOVE.B D0,Q7H(A0) ;and try to put the chip into MFM mode
MOVE.B #IWMMode,Q7H(A0) ;The "magic sequence" is to set bit 6
MOVE.B D0,Q7H(A0) ; to "1", "0", "1", "1" over four
MOVE.B D0,Q7H(A0) ; consecutive accesses
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D2,@0 ;Go verify we're in MFM mode
BRA.S @4 ;Couldn't do it after 2 tries, so return an error
; We're in SWIM mode, so make sure the registers are set up correctly...
@2 MOVE.B #$38,wZeroes(A0) ;Make sure ACTION's cleared
if NonSerializedIO then
nop ; force write to complete <SM5>
endif
MOVE.B #$C0,wIWMConfig(A0) ;Set timer kill + 16MHz timer
if NonSerializedIO then
nop ; force write to complete <SM5>
endif
MOVEQ #$20,D0 ;Init the Setup register to disable the ECM
TST.B mfmDisk(A1,D1) ; is this an MFM disk? <SM5>
BMI.S @MFM ; -> yes <SM5>
MOVEQ #$44,D0 ; GCR setup <SM5>
@MFM ; <SM5>
CMP.B #-2,isSWIM(A1) ; SWIM2? <H9><SM5>
BNE.S @7 ; -> no, setup is fine the way it is <H9><SM5>
TST.B Clock32Mhz(A1) ; do we have a 32Mhz Clock? <H9><SM5>
BEQ.S @7 ; -> no <H9><SM5>
BSET #3,D0 ; yes, set the half speed bit <H9><SM5>
@7 ; <H9><SM5>
MOVE.B D0,wSetup(A0) ; write the setup register <SM5>
if NonSerializedIO then
nop ; force write to complete
endif
CMP.B rSetup(A0),D0 ;Was it written OK?
BNE.S @3 ;-> no, exit with an error
BSR.S SetParams ;Initialize the parameter RAM
BEQ.S @5
@3 MOVE.B #$F8,wZeroes(A0) ;Couldn't init, so shut everything down
if NonSerializedIO then
nop ; force write to complete
endif
@4 TST.B Q7L(A0) ;and return to IWM in a non-write state
MOVEQ #InitIWMErr,D0 ;Return an error
@5 SEQ mfmMode(A1) ;Update the current mode
@6 MOVE (SP)+,SR ;Enable interrupts
TST.W D0 ;Set the CCR
RTS
;______________________________________________________________________________
;
; Routine: SetParams
;
; Inputs: A0 -- pointer to SWIM's base address
; A1 -- pointer to SonyVars
; D1 -- offset to disk's local vars
; track(A1,D1) contains the current track number
;
; Outputs: D0 -- result code (either noErr or InitIWMErr)
;
; Function: Stuffs in the appropriate set of parameters into the SWIM's
; parameter RAM based on which disk zone the current track is in.
; This is called by either SetChipMode or Seek.
;______________________________________________________________________________
SetParams ; <SM5> begin
LEA mParams,A2 ; assume it's MFM mode
TST.B mfmDisk(A1,D1) ; is it?
BMI.S @MFM
LEA gParams,A2 ; no, use the GCR parameter set
@MFM
CMP.B #-2,isSWIM(A1) ; see if this is a SWIM2
BNE.S NotSWIM2 ; -> it's not
MOVE.L D3,-(SP) ; save D3 <H2><H4>
MOVEA.L VIA,A1 ; get VIA1 base address
ADDA.W #VBufD,A1 ; 6522 disk-reg has head sel, wait/req
MOVEQ #5-1,D2 ;give a few tries to set up the params
@1 MOVE.B #$38,wZeroes(A0) ;reset the parameter register counter
SWAP D2 ;(save the loop counter)
MOVEQ #4-1,D0
@2 MOVE.B (A1),(A1) ; access VIA twice to kill some time
MOVE.B rParams(A0),D2 ; read first parm value
MOVE.B rParams(A0),D3 ; clear next value out, it is not used
MOVE.B 0(A2,D0),D3 ; get the value it should be
SUB.B #1,D0 ; decrement by two
LSR.B #4,D2 ; compare high nibbles
LSR.B #4,D3 ; compare high nibbles
CMP.B D2,D3
DBNE D0,@2
BNE.S @3 ;-> no, go stuff the parameters into the chip
MOVEA.L SonyVars,A1 ; restore pointer to SonyVars
MOVE.L (SP)+,D3 ; restore D3
MOVEQ #0,D0 ; parameters all set up, return with no error
RTS
@3 MOVE.B #$38,wZeroes(A0) ;reset the parameter register counter
MOVEQ #4-1,D0
@4 MOVE.B (A1),(A1) ; access VIA twice to kill some time
MOVE.B 0(A2,D0),wParams(A0); and initialize the parameter RAM
DBRA D0,@4
SWAP D2 ;(restore the loop counter)
DBRA D2,@1 ;try again?
MOVEA.L SonyVars,A1 ; restore pointer to SonyVars
MOVE.L (SP)+,D3 ; restore D3
MOVEQ #InitIWMErr,D0 ; couldn't initialize RAM so return an error
RTS
NotSWIM2 ; <SM5> end
MOVEA.L VIA,A1 ; get VIA1 base address <2.1>
ADDA.W #VBufD,A1 ; 6522 disk-reg has head sel, wait/req <2.1>
MOVEQ #5-1,D2 ;give a few tries to set up the params
@1 MOVE.B #$38,wZeroes(A0) ;reset the parameter register counter <1.6>
if NonSerializedIO then
nop ; force write to complete
endif
SWAP D2 ;(save the loop counter) <1.6>
MOVEQ #16-1,D0
@2 MOVE.B (A1),(A1) ; access VIA twice to kill some time <2.1>
if NonSerializedIO then
nop ; force write to complete
endif
MOVE.B rParams(A0),D2 ;check if the parameter values are already set up
CMP.B 0(A2,D0),D2
DBNE D0,@2
BNE.S @3 ;-> no, go stuff the parameters into the chip
MOVEA.L SonyVars,A1 ; restore pointer to SonyVars <2.1>
MOVEQ #0,D0 ;the parameters are all set up so return with no error
RTS
@3 MOVE.B #$38,wZeroes(A0) ;reset the parameter register counter
MOVEQ #16-1,D0
@4 MOVE.B (A1),(A1) ; access VIA twice to kill some time <2.1>
MOVE.B 0(A2,D0),wParams(A0); and initialize the parameter RAM
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,@4
SWAP D2 ;(restore the loop counter)
DBRA D2,@1 ;try again?
MOVEA.L SonyVars,A1 ; restore pointer to SonyVars <2.1>
MOVEQ #InitIWMErr,D0 ;couldn't initialize the parameter RAM so return an error
RTS
; This table contains the last track number+1 and table offset for each of the
; parameter zones on an MFM disk. Different parameter sets can be used to
; optimize the error correction performance to handle variations in peak shift,
; drive speed, etc.
mParamZones DC.W 80,mParams-mParamZones ;change back after getting the 2nd parm set right
DC.W 80,mParams+16-mParamZones
DC.W 80,mParams-mParamZones
DC.W 80,mParams-mParamZones
; Parameter register values in reverse order.
;
; The timing values Time1, Time0, xSx, xLx and Min have a resolution to
; the nearest half clock, so their actual register values are doubled so
; that bits 1-7 become the integer part and bit 0 becomes the ".5" part.
; xSx and xLx are reduced by 2 clocks, and Min is reduced by 3 clocks to
; take into account gate delays in the SWIM.
; For a 15.6672MHz input clock (Mac SE, Mac II, etc):
mParams DC.B (31-2)*2+1 ;[F] Time1 = 31.5
DC.B $57 ;[E] Early/Norm = $57
DC.B (15-2)*2+1 ;[D] Time0 = 15.5
DC.B $97 ;[C] Late/Norm = $97
DC.B (14-2)*2+1 ;[B] LLS = 14.5
DC.B (14-2)*2+1 ;[A] LLL = 14.5
DC.B (25-2)*2+1 ;[9] LSS = 25.5
DC.B (25-2)*2+1 ;[8] LSL = 25.5
DC.B (15-2)*2+1 ;[7] CSLS = 15.5
DC.B (15-2)*2+1 ;[6] RPT = 15.5
DC.B (14-2)*2+0 ;[5] SLS = 14.0
DC.B (14-2)*2+0 ;[4] SLL = 14.0
DC.B (25-2)*2+0 ;[3] SSS = 25.0
DC.B (25-2)*2+0 ;[2] SSL = 25.0
DC.B 65 ;[1] Mult = 65
DC.B (15-3)*2 ;[0] Min = 15.0
gParams DC.B (32-2)*2+0 ;[F] Time1 = 32.0 <SM5> begin
DC.B (8*16)+8 ;[E] Early/Norm = 8 / 8
DC.B (32-2)*2+0 ;[D] Time0 = 32.0
DC.B (8*16)+8 ;[C] Late/Norm = 8 / 8
DC.B (32-2)*2+0 ;[B] LLS = 32.0
DC.B (32-2)*2+0 ;[A] LLL = 32.0
DC.B (32-2)*2+0 ;[9] LSS = 32.0
DC.B (32-2)*2+0 ;[8] LSL = 32.0
DC.B (32-2)*2+0 ;[7] CSLS = 32.0
DC.B (32-2)*2+0 ;[6] RPT = 32.0
DC.B (32-2)*2+0 ;[5] SLS = 32.0
DC.B (32-2)*2+0 ;[4] SLL = 32.0
DC.B (32-2)*2+0 ;[3] SSS = 32.0
DC.B (32-2)*2+0 ;[2] SSL = 32.0
DC.B 64 ;[1] Mult = 64
DC.B (16-3)*2+0 ;[0] Min = 16.0 <SM5> end
; Alternate parameter sets which may be used in the future or removed entirely.
; For now they simply occupy 32 (2*16) bytes of space so we don't have to worry
; about shuffling pieces of the driver about ROM when parameter changes come along.
DC.B $53,$4F,$2E,$2E,$2E,$57,$48,$41,$54,$20,$41,$52,$45,$20,$59,$4F
DC.B $55,$20,$53,$54,$41,$52,$49,$4E,$47,$20,$41,$54,$3F,$20,$20,$20
;______________________________________________________________________________
;
; Routine: ChkDiskType
;
; Inputs: A0 -- pointer to IWM/SWIM base address
; A1 -- pointer to SonyVars
; D1 -- offset to disk's local vars
; mfmDisk(A1,D1)=0
;
; Outputs: mfmDisk(A1,D1) is set depending on the disk format type.
; If it's an MFM disk, twoMegFmt(A1,D1) is set accordingly.
;
; Function: Checks whether an MFM or GCR disk has just been inserted.
; On entry, the drive is powered up for GCR and DiskInPlace(A1,D1)=2.
; If a 1440K disk is formatted as a GCR 400K or 800K disk, it will
; set DiskInPlace(A1,D1) to 3 to indicate the fact (but also to mark
; it as clamped for anyone that cares), and return with a special
; error for the format package to figure out.
;
; Note that ChkDiskType can't be called as a subroutine since it
; must be on the same stack level as DiskPrime because WakeUp gets
; called (from Recal).
;______________________________________________________________________________
ChkDiskType MOVE.B isSWIM(A1),D0 ;Are we using a SWIM
AND.B mfmDrive(A1,D1),D0 ;and a SuperDrive?
BPL.S @2 ;-> no, just return
MOVEQ #TwoMegAdr,D0 ;Check for double-density disk
BSR AdrAndSense
SPL twoMegFmt(A1,D1) ;$FF if so
BSR.S GetASector ;Try to find a GCR sector
TST.W D0
BMI.S @0 ;-> it's not GCR, but it might be MFM
MOVE.B twoMegFmt(A1,D1),mfmDisk(A1,D1) ;is this a 1440K disk?
BPL.S @2
ADDQ.B #1,DiskInPlace(A1,D1) ;make it 3 to signal weird format, but clamped
MOVE.W #GCRonMFMErr,D0 ;yes, we won't allow it to be used in GCR mode
BRA DskRWOff
@0 ST mfmDisk(A1,D1) ;Now try for an MFM disk
BSR Recal ;Select the SWIM regs + power up drive in MFM mode
BNE.S @1 ;-> error
TST.B twoMegFmt(A1,D1) ;is this a 1440K disk?
BMI.S @2 ;-> yes, it's gotta be MFM
BSR.S GetASector ;Try to find an MFM sector
SUBI.B #$22,D3 ;We only support type 2 (512 byte blocks)
OR.W D3,D0 ;No error too?
BEQ.S @2 ;-> yes, all done
@1 MOVE.B twoMegFmt(A1,D1),mfmDisk(A1,D1) ;MFM if no error and right format type
; -OR- it's a double-density disk
@2 BRA CkWrProt ;Back to Prime where we left off...
GetASector MOVEQ #5,D1
@1 MOVE.W D1,-(SP) ;Save the retry counter
MOVE SR,-(SP) ;Save the interrupt level
CLR.W SideTrack(A1) ;Make sure we read off of side 0 (just in case it's 400K)
BSR RdAddrSetup ;Try to find a sector
BSR EmptyPD ;Get rid of any SCC data (sets up A1,D1)
MOVE (SP)+,SR ;Restore the interrupt state
MOVE.W (SP)+,D1 ;and the retry counter
TST.W D0 ;Was the read successful?
DBPL D1,@1 ;-> loop if not
BRA GetDrv1 ;Setup A1,D1
;______________________________________________________________________________
;
; Routine: mAdrDisk
;
; Inputs: D0 -- drive address ([ca1][ca0][sel][ca2])
; D1 -- word offset of current drive's specific vars
; A0 -- IWM base ptr
; A1 -- pointer to driver variables
; A2 -- VIA base ptr
;
; Outputs: same
;
; Function: Selects the input drive address by manipulating the phase lines
; in the SWIM and the HDSEL line in the VIA.
;______________________________________________________________________________
mAdrDisk MOVE.B #$F3,wPhase(A0) ;CA0,CA1 must be 1 when changing SEL to zero
if NonSerializedIO then
nop ; force write to complete
endif
BTST #1,D0 ;Is SEL high or low? <SM5>
BEQ.S @1 ; <SM5>
MOVE.B #$20,wOnes(A0) ;high <SM5>
BRA.S @2 ; <SM5>
@1 MOVE.B #$20,wZeroes(A0) ;low <SM5>
@2 BTST #1,D0 ;Is SEL high or low? <SM5>
BEQ.S @3
BSET #VHeadSel,VBufD(A2) ;high
BRA.S @4
@3 BCLR #VHeadSel,VBufD(A2) ;low
@4 MOVE.B mPhaseTbl(D0),wPhase(A0) ;Set the rest of the lines
if NonSerializedIO then
nop ; force write to complete
endif
RTS
mPhaseTbl DC.B $F0,$F4,$F0,$F4,$F1,$F5,$F1,$F5,$F2,$F6,$F2,$F6,$F3,$F7,$F3,$F7,$53,$57,$43,$21
;______________________________________________________________________________
;
; Routine: mSense
;
; Inputs: D1 -- word offset of current drive's specific vars
; A0 -- IWM base ptr
; A1 -- pointer to driver variables
; A2 -- VIA base ptr
;
; Outputs: D0 -- drive status (in bit 7)
;
; Function: Reads the state of the currently-selected drive address.
;______________________________________________________________________________
mSense BTST #3,rHandshake(A0) ;Read the sense bit
SNE D0 ;and move it to bit 7
TST.B D0 ;Set the CCR
RTS
;______________________________________________________________________________
;
; Routine: mPulse
;
; Inputs: D1 -- word offset of current drive's specific vars
; A0 -- IWM base ptr
; A1 -- pointer to driver variables
; A2 -- VIA base ptr
;
; Outputs: same
;
; Function: Strobes the LSTRB (phase 3) line to execute a drive command
; corresponding to the currently-selected drive address.
;______________________________________________________________________________
mPulse MOVE SR,-(SP) ;Disable interrupts
ORI #HiIntMask,SR
MOVE.L D0,-(SP) ;Save D0 just in case
MOVEQ #%11111000-256,D0 ;Mask with phase 3 turned on
OR.B rPhase(A0),D0 ; and add in the states of phases 0-2
MOVE.B D0,wPhase(A0) ;Toggle phase 3 high...
if NonSerializedIO then
nop ; force write to complete
endif
MOVE.B VBufD(A2),VBufD(A2) ; access VIA to kill some time <2.1>
SUBQ.B #8,D0
MOVE.B D0,wPhase(A0) ;...then low
if NonSerializedIO then
nop ; force write to complete
endif
MOVE.L (SP)+,D0 ;Restore D0
MOVE (SP)+, SR ;Enable interrupts
RTS
;______________________________________________________________________________
;
; Routine: mDiskSelect
;
; Inputs: A0 -- pointer to SWIM base address
; A1 -- pointer to SonyVars
; A2 -- pointer to VIA base address
; D1 -- offset to current drive's variables
;
; Outputs: same as input
;
; Function: Finishes the interface selection if we're in MFM mode (SWIM regs).
;______________________________________________________________________________
mDiskSelect
CMP.W #drive1,D1 ;If Drive=1, it's internal
BNE.S @1 ;-> it's not
MOVE.B #$04,wZeroes(A0) ;Disable the external drive and
MOVE.B #$82,wOnes(A0) ;enable the internal one
if NonSerializedIO then
nop ; force write to complete
endif
RTS
@1 MOVE.B #$F7,wPhase(A0) ;Go to state 7 in case we're enabled
if NonSerializedIO then
nop ; force write to complete
endif
BCLR #vHeadSel,VBufD(A2) ; set HdSel low (/Exists addr) <SM5>
MOVE.B #$20,wZeroes(A0) ; <SM5>
MOVE.B #$02,wZeroes(A0) ;Disable the internal drive and
MOVE.B #$84,wOnes(A0) ;enable the external one
if NonSerializedIO then
nop ; force write to complete
endif
RTS
;______________________________________________________________________________
;
; Routine: mGetTrack
;
; Inputs: A0 -- pointer to caller's parameter block
; A1 -- pointer to SonyVars
; A2 -- pointer to driver's DCE
; D0 -- absolute disk block number
; D1 -- offset to drive's local vars
; D7 -- 9 (2^9=512)
;
; Outputs: D0 -- first sector we want on this track - 1
; D2 -- -1
; D3 -- number of sectors/track + 1
; D5 -- track we're on
; D6 -- zero if side zero
;
; Function: Converts a block number into track, head, sector.
;______________________________________________________________________________
mGetTrack MOVEQ #90,D2 ;Assume 720K disk: 1440 blocks/16=90
LSL.W #4,D2 ;(multiply by 16 to get total blocks/disk)
MOVEQ #9,D3 ;Number of blocks/track (one side)
TST.B twoMegFmt(A1,D1) ;Is this a double-density disk?
BPL.S @1
ADD.W D2,D2 ;Yes, 1440K disk: twice as many blocks
MOVEQ #18,D3 ; and sectors
@1 CMP.L D2,D0 ;Block number past end-of-disk?
BGE DskParmErr ;-> yes, return an error
DIVU D3,D0 ;D0.L=[first sector][2*track+side]
LSR.W #1,D0 ;Extract the side number:
SCS D6 ;$00=side 0, $FF=side 1
MOVE.W D0,D5 ;D5=desired track
SWAP D0 ;D0.W=first sector we want - 1
MOVEQ #-1,D2
ADDQ.W #1,D3
BRA gtResume ;Pick up where we left off (SonyRWT)
;_______________________________________________________________________________
;
; Routine: mRdAddr
;
; Inputs: A2 -- pointer to mAddrMarks table
; A5 -- ptr to 6522 A-reg (has head sel, wait/req)
; A6 -- ptr to SCC A-channel data register
;
; Outputs: A3 -- pointer to rHandshake
; A4 -- pointer to rMark
; D0 -- result code
; D1 -- <side><track> (low-order 12 bits)
; D2 -- <sector>
; D3 -- <block size code>+$20 (this should be $22 for 720K and 1440K disks)
;
; A0,D4,D5 are trashed
;
; Function: This routine reads the next address mark that spins by. On exit,
; the attributes of the mark are passed back as shown above.
;
; The disk should be up to speed with the correct head selected, the
; SWIM registers should be selected, and interrupts should be disabled.
;_______________________________________________________________________________
mAddrMarks DC.B $A1,$A1,$A1,$FE
mRdAddr LEA mAddrMarks,A2 ;Point to our address mark table
MOVE.L jMRdAddr,-(SP)
RTS
jtMRdAddr MOVE.L (SP)+,DskRtnAdr ;Save return address
LEA TagData+2,A0
CLR.L (A0)+ ;Zero out the TagData
CLR.L (A0)+
CLR.L (A0)+
MOVEA.L IWM,A4
LEA rHandshake(A4),A3 ;Point to handshake and
LEA rMark(A4),A4 ;mark registers for speed
; Try to find the next address mark. We give a certain amount of time to try to
; find an address mark before timing out. This means that many addresss marks
; (both real and imagined) may be seen since depending on how we sync up with
; the data spinning by, normal bytes can take on a sinister "mark" alias...
MOVEQ #NoAdrMkErr,D0 ;assume we can't find an address mark
MOVE.W #mSctrTOCnt,D2 ;timeout counter (needs to be tuned)
RdAddrMark TST.B rError-rMark(A4) ;clear the error register
MOVE.B #$18,wZeroes-rMark(A4) ;clear the write and action bits <SM5>
MOVE.B #$01,wOnes-rMark(A4) ;toggle the clFIFO bit to clear out <SM5>
MOVE.B #$01,wZeroes-rMark(A4) ; any data in the FIFO <SM5>
if NonSerializedIO then
nop ; force write to complete
endif
BTST #5,rHandshake-rMark(A4) ; check to see if there are any errors <SM5>
BEQ.S @0 ; -> no, continue <SM5>
TST.B rError-rMark(A4) ; yes, clear the error register <SM5>
@0 MOVE.B #$08,wOnes-rMark(A4) ;turn on the action bit: GO! <SM5>
if NonSerializedIO then
nop ; force write to complete
endif
MOVEA.L A2,A0 ;point to our mark table <SM5>
MOVEQ #markSize-1,D1
@1
TST.B (A5) ; throttle execution speed with a VIA access<SM5>
BTST #RxCA,aCtl-aData(A6) ; SCC data available? <SM5>
BEQ.S @2
MOVE.B (A6),-(SP) ; yes, push it on the stack <SM5>
@2 TST.B (A3) ;wait for an address mark byte <SM5>
DBMI D2,@1
BPL ReadExit ;-> timed out (return "No Address Mark") <SM5>
MOVE.B (A4),D5 ;get a byte <SM5>
CMP.B (A0)+,D5 ;is it a correct mark byte? <SM5>
DBNE D1,@1
BEQ.S RdAddrMarkDone ;-> yes, branch back into mainline code <H18><SM5>
MOVE.B #$08,wZeroes-rMark(A4) ;-> no, clear the write and action bits <H18><SM5>
BRA.S RdAddrMark ; and start over <H18><SM5>
RdAddrMarkDone ; <SM5>
; We found an address mark so retrieve the information from the ID field...
MOVEQ #mByteTOCnt,D0
RdAddrField TST.B (A3) ;Wait for a byte
DBMI D0,RdAddrField
BPL.S RdAddrTO ;-> timed out
MOVEQ #0,D1
MOVE.B (A4),D1 ;Read the cylinder
LEA TagData+2,A0 ;We'll return sector info in the tags
MOVE.B D1,(A0)+ ; like the cylinder number
MOVEQ #mByteTOCnt,D0
@1 TST.B (A3) ;Wait for a byte
DBMI D0,@1
BPL.S RdAddrTO ;-> timed out
MOVE.B (A4),(A0)+ ;Which side is it?
BEQ.S @2
BSET #11,D1 ;Side 1: set bit 11
@2 MOVEQ #mByteTOCnt,D0
MOVEQ #0,D2
@3 TST.B (A3) ;Wait for a byte
DBMI D0,@3
BPL.S RdAddrTO ;-> timed out
MOVE.B (A4),D2 ;Read the sector
MOVE.B D2,(A0)+
_PollSCC ; poll the SCC modem port <H4><SM5>
@4 MOVEQ #mByteTOCnt,D0
MOVEQ #$20,D3 ;(this is so we look double-sided)
@5 TST.B (A3) ;Wait for a byte
DBMI D0,@5
BPL.S RdAddrTO ;-> timed out
OR.B (A4),D3 ;Read the block size
MOVE.B D3,(A0)+
MOVEQ #badCkSmErr,D0 ;Assume CRC error
BRA CheckCRC ;Now go check the CRC
RdAddrTO BRA ReadTOErr
;_______________________________________________________________________________
;
; Routine: mRdData
;
; Inputs: A0 -- pointer to data buffer
; A1 -- pointer to mDataMarks table
; A3 -- pointer to rHandshake
; A4 -- pointer to rMark
; A5 -- pointer to 6522 A-reg (has head sel, wait/req)
; A6 -- pointer to SCC channel A data register
;
; Outputs: D0 -- result code
;
; A0-A2,D1-D2,D4-D5 are trashed
; (don't play with D3 since mVerTrack uses it)
;
; Function: This routine reads the next data mark that spins by, then reads
; the 512-byte data block into the buffer pointed to by A0.
;
; The disk should be up to speed with the correct head selected,
; and interrupts should be disabled. This routine should be
; called immediately after RdAddr for disk reads.
;_______________________________________________________________________________
mDataMarks DC.B $A1,$A1,$A1,$FB
mRdData LEA mDataMarks,A1
MOVE.L jMRdData,-(SP)
RTS
jtMRdData MOVE.L (SP)+,DskRtnAdr ;Save return address
MOVE.W #2-1,D4 ; loop count for invalid mark bytes <H9><SM5>
; Try to find a valid data mark (the next mark must be a data mark or something's wrong)
RdDataMarkStart ; <H9><SM5>
TST.B rError-rMark(A4) ;Clear the error register
MOVE.B #$18,wZeroes-rMark(A4) ;Clear the write and action bits
MOVE.B #$01,wOnes-rMark(A4) ;Toggle the clFIFO bit to clear out
MOVE.B #$01,wZeroes-rMark(A4) ;any data in the FIFO
TST.B rError-rMark(A4) ;Clear the error register again for grins
MOVE.B #$08,wOnes-rMark(A4) ;Turn on the action bit: GO!
if NonSerializedIO then
nop ; force write to complete
endif
MOVEQ #noDtaMkErr,D0 ;Assume error
MOVEQ #markSize-1,D1 ; <SM5>
MOVEQ #-1,D2 ; timeout counter (needs to be tuned) <SM5>
MOVE.L A1,D5 ; <SM5>
MOVEA.L SonyVars,A1 ; <SM5>
CMPI.B #-2,isSWIM(A1) ; are we using a SWIM2? <SM5>
MOVEA.L D5,A1 ; <SM5>
BNE.S RdDataMark ; -> nope <SM5>
@Wait4Mark _PollSCC ; poll the SCC modem port <H5><SM5>
MOVE.B (A3),D5 ; wait for a data mark <SM5>
DBMI D2,@Wait4Mark ; <SM5>
BPL ReadTOErr ; -> timed out <SM5>
BTST #0,D5 ; is it a mark byte? <SM5>
BNE GotDataMark ; -> yes, go for it <SM5>
MOVE.B (A4),D5 ; read a garbage byte <SM5>
BRA.S @Wait4Mark ; -> keep trying <SM5>
RdDataMark _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A3) ;Wait for a data mark
DBMI D2,RdDataMark
BPL.S jReadTOErr ;-> timed out
GotDataMark MOVEQ #mByteTOCnt,D2 ;reset the timeout counter for the next byte<SM5>
MOVE.B (A4),D5 ; and read in the current byte
CMP.B (A1)+,D5 ;is it a correct data mark?
DBNE D1,RdDataMark
BEQ.S @1 ;-> yes, continue reading sector data <SM5>
MOVE.B #$08,wZeroes-rMark(A4) ;-> no, clear the write and action bits <SM5>
if NonSerializedIO then
nop ; force write to complete <SM5>
endif
LEA mDataMarks,A1 ; reset pointer to data mark field <SM5>
DBRA D4,RdDataMarkStart ; start again, we will try twice <SM5>
BRA ReadExit ; After second try, exit with noDataMkErr<SM5>
@1
MOVE.W #512-1,D4 ; Initialize number of bytes to read <SM5>
TST.B DskVerify ; Are we comparing? <SM5>
BNE.S VfyDataBlk ;-> yes
; We found a data mark so retrieve the data block...
RdDataBlk TST.B (A3) ;do a quick check for a byte
BMI.S @2 ;-> it's already ready
MOVEQ #mByteTOCnt,D1 ;timeout counter
_PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A3) ;wait for a data byte
DBMI D1,@1
BPL.S jReadTOErr ;-> timeout
@2 MOVE.B (A4),(A0)+ ;read the data byte and save it
DBRA D4,RdDataBlk
BRA.S CheckDCRC
jReadTOErr BRA.S ReadTOErr
; We found a data mark so compare the data being read with what we just wrote...
VfyDataBlk TST.B (A3) ;do a quick check for a byte
BMI.S @2 ;-> it's already ready
MOVEQ #mByteTOCnt,D1 ;timeout counter
_PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A3) ;wait for a data byte
DBMI D1,@1
BPL.S jReadTOErr ;-> timeout
@2 MOVE.B (A4),D2 ;read a data byte
CMP.B (A0)+,D2 ;does it match what it's expected to be?
DBNE D4,VfyDataBlk ;keep looping if so (until done, that is)
BNE.S VerifyErr ;-> nope, report an error
; Finally, check the 16-bit CRC to make sure the data's all correct. We check
; for CRC error after reading the first CRC byte but before reading the second.
; From here to the RTS, D1-D3 must be preserved 'cause this code is shared by mRdAddr.
CheckDCRC MOVEQ #badDCkSum,D0 ;Assume error
LEA TagData+10,A0 ;Include the CRC in the TagData
CheckCRC MOVEQ #mByteTOCnt,D4 ;Timeout counter
@1 TST.B (A3) ;Wait for the first CRC byte
DBMI D4,@1
BPL.S ReadTOErr ;-> timeout
MOVE.B (A4),(A0)+ ;Save it in case we want it later
MOVEQ #mByteTOCnt,D4 ;Timeout counter
@2 TST.B (A3) ;Wait for the second CRC byte <H11><SM5>
DBMI D4,@2
BPL.S ReadTOErr ;-> timeout
MOVE.B (A3),D5 ;Get the handshake register with valid bits <SM5>
MOVE.B (A4),(A0)+ ;Save the CRC byte in case we want it later
MOVE.B rError-rMark(A4),(A0)+ ;Stuff the error register into tags
MOVE.B D5,(A0) ;followed by the handshake register
ANDI.B #%00100010,D5 ;CRC error or something in the error register?
BNE.S ReadExit
MOVEQ #0,D0 ;No, the data's OK
; Now turn off the hardware...
ReadExit MOVE.B #$18,wZeroes-rMark(A4) ;Clear the write and action bits
if NonSerializedIO then
nop ; force write to complete
endif
MOVE.L DskRtnAdr,-(SP)
TST.W D0
RTS
ReadTOErr MOVEQ #dataTOErr,D0 ;Timed out waiting for a byte
BRA.S ReadExit
VerifyErr MOVEQ #dataVerErr,D0 ;No, report the error
BRA.S ReadExit
;_______________________________________________________________________________
;
; Routine: mWrData
;
; Inputs: A0 -- pointer to data buffer
; A2 -- pointer to data mark table
; A5 -- pointer to 6522 A-reg (has head sel, wait/req)
; A6 -- pointer to SCC channel A data register
;
; Outputs: D0 -- result code
;
; A0,A1,D1,D2 are trashed
;
; Function: This routine writes 12 sync bytes, 4 data mark bytes, the data buffer,
; and 2 CRC bytes. There is no other overhead so it may be used for
; one-to-one writing.
;
; Since timing is tight coming into this routine, the disk write-protect
; sense line should be checked by the read/write track logic.
;_______________________________________________________________________________
mWrData LEA mDataMarks,A2
MOVE.L jMWrData,-(SP)
RTS
jtMWrData MOVE.L (SP)+,DskRtnAdr ;Save return address
MOVEA.L IWM,A4
LEA wData(A4),A3 ;Point to write data and
LEA rHandshake(A4),A4 ; handshake registers for speed
MOVE.B #$F5,wPhase-wData(A3) ;select another drive address (in this case x101) <1.3/19may88>
; to avoid the drive's index crosstalk problem <1.3/19may88>
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
if NonSerializedIO then
nop ; force write to complete
endif
TST.B rError-wData(A3) ;Clear the error register again for grins
; Delay a bit then write the sync bytes before the data mark to position
; the sector data in the correct location relative to the address header.
; We'll poll the SCC while we wait to keep the CompuServe types happy that
; we're not losing precious bytes of gossip while we're saving stuff to disk...
MOVE.W #((gap2Size*16-reWriteAdj)<<16)\ ; <2.0>
/1000,D0 ; write splice timing constant <2.0>
;Calculate how much time we have to wait before
MULU TimeVIADB,D0 ; beginning to re-write the sector data. It needs to be <2.0>
SWAP D0 ; positioned close to 22 bytes from the end of the address field.
@1 BTST.B #7,(A5) ;SCC data available? (TimeSCCDB assumes BTST in loop)
DBEQ D0,@1 ;keep looping if not (until timing out, that is)
BNE.S @2 ;-> all done waiting
MOVE.B (A6),-(SP) ;data byte available so push it on the stack
SUBQ.W #2,D0 ;adjust for the missed DBEQ + the MOVE.B
BPL.S @1 ;-> wait some more
; OK, now we should be in the right position to start writing the sync bytes...
@2 MOVEQ #syncSize-2-1,D0
MOVEQ #theSync,D1
MOVE.B D1,(A3) ;Write the first two sync bytes
MOVE.B D1,(A3) ; to fill up the FIFO
MOVE.B #$08,wOnes-wData(A3);Turn on the ACTION bit and go!
if NonSerializedIO then
nop ; force write to complete
endif
WriteSync _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4) ;Wait until there's an opening in the FIFO
BPL.S @1
MOVE.B D1,(A3) ;Write out a sync byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,WriteSync
; Write the data marks...
MOVEQ #markSize-1-1,D0
WrDataMark _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4)
BPL.S @1
MOVE.B (A2)+,wMark-wData(A3) ;Write out a mark byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,WrDataMark
@2 TST.B (A4)
BPL.S @2
MOVE.B (A2),(A3) ;Write out the last mark byte
if NonSerializedIO then
nop ; force write to complete
endif
; Write the sector data...
MOVE.W #512-1,D0
WrDataBlk _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4)
BPL.S @1
MOVE.B (A0)+,(A3) ;Write out a data byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,WrDataBlk
; End the sector data with 2 CRC bytes...
WriteCRC TST.B (A4)
BPL.S WriteCRC
MOVE.B D0,wCRC-wData(A3)
if NonSerializedIO then
nop ; force write to complete
endif
; Then finally add a few gap bytes so that the CRC
; will be fully written before writing is disabled...
;
; FIFO1: CRC | gap1 | gap2 | gap2 | gap3
; FIFO2: data512 | CRC | gap1 | gap1 | gap2
; ShiftReg: data511 | data512 | CRC1 | CRC2 | gap1
MOVEQ #4-1,D0
WrtGap3 _PollSCC ; poll the SCC modem port <H4><SM5>
@1 MOVE.B (A4),D2
BPL.S @1
MOVE.B #gapByte,(A3) ;Write out a gap byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,WrtGap3
MOVEQ #0,D0 ;Assume no underrun
BTST #5,D2 ;Any errors?
BEQ.S WriteExit
MOVEQ #WrUnderRun,D0 ;Yes, underrun error
WriteExit 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
;______________________________________________________________________________
;
; Routine: mFmtTrack
;
; 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.
;______________________________________________________________________________
mFmtTrack 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
MOVE.W TimeDBRA,D2 ;wait 750usec before switching heads or the drive
MOVE.L D2,D0 ; will ignore us, and then where will we be?
ADD.L D2,D0
ADD.L D2,D0
LSR.L #2,D0
@0 DBRA D0,@0 ;just sit here for a bit...
@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.S mDoFormat ;Format the track (disables interrupts)
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 @3 ;-> yes, return immediately
BSR GetDrv1 ;Point to drive vars
BSET #3,SideTrack(A1) ;Is this the second side?
BEQ.S mFmtTrack ;-> no, go format it now
MOVEQ #0,D0 ;Format was successful
@3 RTS
;_______________________________________________________________________________
;
; Routine: mDoFormat
;
; Inputs: D2 -- sectors/track - 1 (8 or 17); if 17, bit 31 will be set=1
; D4 -- track
; D5 -- side
;
; Outputs: 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) [ 80]
; Sync bytes ($00) [ 12]
; C2 C2 C2 FC (index mark) [ 4]
; Gap bytes ($4E) [ 50]
;
; then 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, 101 for 1440K]
;
; loop for all sectors (9 for 1MB, 18 for 2MB)
;
; write gap bytes until the rising edge of index is sensed
;_______________________________________________________________________________
mDoFormat 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 IWM,A4
LEA wData(A4),A3 ;Point to the write data and
LEA rHandshake(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 <SM5>
TST.B rError-wData(A3) ; clear the error register again <SM5>
; 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 <H4><SM5>
@1 MOVE.B (A4),D0 ;Wait until there's an opening in the FIFO
BPL.S @1
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 <H4><SM5>
@1 MOVE.B (A4),D0 ;Wait until there's an opening in the FIFO
BPL.S @1
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 <1.3/19may88>
if NonSerializedIO then
nop ; force write to complete
endif
MOVEQ #gap4aSize-1-1,D0 ; <1.8>
@1 _PollSCC ; poll the SCC modem port <H4><SM5>
@2 TST.B (A4) ;Wait until there's an opening in the FIFO <1.8>
BPL.S @2 ; <1.8>
MOVE.B D1,(A3) ;Write out a gap byte <1.8>
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,@1 ; <1.8>
MOVEQ #syncSize-1,D0 ; <1.8>
MOVEQ #theSync,D1 ; <1.8>
@3 _PollSCC ; poll the SCC modem port <H4><SM5>
@4 TST.B (A4) ;Wait until there's an opening in the FIFO <1.8>
BPL.S @4 ; <1.8>
MOVE.B D1,(A3) ;Write out a sync byte <1.8>
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,@3 ; <1.8>
; Now write the index mark ($C2 $C2 $C2 $FC)...
MOVEQ #markSize-1-1,D0 ; <1.8>
WrIndexMark _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4) ;Wait until there's an opening in the FIFO <1.8>
BPL.S @1 ; <1.8>
MOVE.B #$C2,wMark-wData(A3);Write out an index mark byte <1.8>
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,WrIndexMark ; <1.8>
@2 TST.B (A4) ;Wait until there's an opening in the FIFO <1.8>
BPL.S @2 ; <1.8>
MOVE.B #$FC,(A3) ;Write out the last mark byte <1.8>
if NonSerializedIO then
nop ; force write to complete
endif
; Write another gap...
MOVEQ #gap1Size-1,D0 ; <1.8>
FmtGap1 _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4) ;Wait until there's an opening in the FIFO <1.8>
BPL.S @1 ; <1.8>
MOVE.B #gapByte,(A3) ;Write out a gap byte <1.8>
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,FmtGap1 ; <1.8>
MOVEQ #1,D6 ;Starting sector number
BRA.S FmtAddrSync ;Start a sector with the address mark sync
; Tack yet another gap onto the end of the sector...
FmtNextSect 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 <H4><SM5>
@1 TST.B (A4)
BPL.S @1
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...
FmtAddrSync MOVEQ #syncSize-1,D0
MOVEQ #theSync,D1
@1 _PollSCC ; poll the SCC modem port <H4><SM5>
@2 TST.B (A4) ;Wait until there's an opening in the FIFO
BPL.S @2
MOVE.B D1,(A3) ;Write out a sync byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,@1
; Write the address mark and field...
MOVEQ #markSize-1-1,D0
FmtAddrMark _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4)
BPL.S @1
MOVE.B #$A1,wMark-wData(A3);Write out a mark byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,FmtAddrMark
@2 TST.B (A4)
BPL.S @2
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 <H4><SM5>
@3 TST.B (A4)
BPL.S @3
MOVE.B D4,(A3) ;Write the track number
if NonSerializedIO then
nop ; force write to complete
endif
_PollSCC ; poll the SCC modem port <H4><SM5>
@4 TST.B (A4)
BPL.S @4
MOVE.B D5,(A3) ;Write the side number
if NonSerializedIO then
nop ; force write to complete
endif
_PollSCC ; poll the SCC modem port <H4><SM5>
@5 TST.B (A4)
BPL.S @5
MOVE.B D6,(A3) ;Write the sector number
if NonSerializedIO then
nop ; force write to complete
endif
_PollSCC ; poll the SCC modem port <H4><SM5>
@6 TST.B (A4)
BPL.S @6
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...
FmtAddrCRC _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4)
BPL.S @1
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 <H4><SM5>
@1 TST.B (A4)
BPL.S @1
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
@2 _PollSCC ; poll the SCC modem port <H4><SM5>
@3 TST.B (A4)
BPL.S @3
MOVE.B D1,(A3) ;Write out a sync byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,@2
; Write the data marks...
MOVEQ #markSize-1-1,D0
FmtDataMark _PollSCC ; poll the SCC modem port <H4><SM5>
@1 TST.B (A4)
BPL.S @1
MOVE.B #$A1,wMark-wData(A3);Write out a mark byte
if NonSerializedIO then
nop ; force write to complete
endif
DBRA D0,FmtDataMark
@2 TST.B (A4)
BPL.S @2
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 <H4><SM5>
@1 TST.B (A4)
BPL.S @1
MOVE.B #fmtFillByte,(A3) ;Write out a format 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,FmtNextSect
; 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 <1.4/25may88>
MOVEQ #gapByte,D1
MOVE.W #gap4bSize,D3
TST.W D5 ;is this side 0?
BNE.S FmtLastGap
MOVEQ #5-1,D3 ;yes, use the Reader's Digest gap size... <1.4/25may88>
BRA.S FmtLastGap ; <1.3/19may88>
TurnIndexOn MOVE.B #$F4,wPhase-wData(A3) ;turn the index signal back on here <1.3/19may88>
; so there's no glitch in the data <1.3/19may88>
if NonSerializedIO then
nop ; force write to complete
endif
FmtLastGap _PollSCC ; poll the SCC modem port <H4><SM5>
@1 MOVE.B (A4),D2 ;Wait until there's an opening in the FIFO
BPL.S @1
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 @2 ;-> nope <1.3/19may88>
BEQ.S TurnIndexOn ;-> turn index back on before we check it <1.3/19may88>
BTST #3,D2 ;Is index pulse high?
BNE.S FmtDone ;-> yes, all done
@2 DBRA D3,FmtLastGap
TST.W D5 ;is this side 0?
BEQ.S FmtDone ;-> yes, we don't care if we don't see index
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
;_______________________________________________________________________________
;
; Routine: mVerTrack
;
; Inputs: A1 -- pointer to SonyVars
; D1 -- offset to drive's vars
; D6 -- current track number
;
; Outputs: D0 -- result code
;
; Function: Verifies that all sectors (both sides) have been written correctly.
;_______________________________________________________________________________
mVerTrack MOVEM.L D2-D7,-(SP)
ORI #HiIntMask,SR ;No interrupts
MOVE.W D6,SideTrack(A1) ;Start on side 0
@1 MOVEQ #4*9,D7 ;Assume 1 meg format (allow several revs) <1.8>
MOVE.L #$000003FE,D6 ;Sector map (1-9)
TST.B twoMegFmt(A1,D1) ;Is this a double-density disk?
BPL.S @2
MOVEQ #4*18,D7 ;Yes, twice as many sectors <1.8>
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
MOVEA.L DiskBuffer(A1),A0 ;Get someplace to put the data
CLR.B DskVerify ;Never verify even tho' we are (verifying)
BSR mRdData ;Read in 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
BRA.S @5 ; verify every sector for some reason
@4 BSET #3,SideTrack(A1) ;Is this the second side?
BEQ.S @1 ;-> no, go verify it
@5 ANDI #$F8FF,SR ;Turn interrupts back on
MOVEM.L (SP)+,D2-D7
TST.W D0
RTS
;_______________________________________________________________________ <SM5> begin
;
; Routine: jtISMRdAddr
; Arguments:
; A5.L (input) -- ptr to 6522 A-reg (has head sel, wait/req)
; A6.L (input) -- ptr to SCC A-channel data register
; A2.L (input) -- pointer to AdrMks table
; D0.W (output) --
; 0-1499 = no error, 1500 - nybbles before address mark
; -66 = no transitions found
; -67 = no address mark found (no header read)
; -68 = bad data nybble (header read aborted)
; -69 = bad checksum (header read but is inconsistent)
; -70 = bad bit slip marks (header read but may be bad)
; D1.W (output) -- <side><track> (low-order 12 bits)
; D2.W (output) -- <sector>
; D3.W (output) -- <volume>
; A3.L (output) -- ptr to <DNib-$96> (denibblizing table)
; A4.L (output) -- DiskQ6L pointer
; D4,D5,A0,A2 are trashed
; D6-D7 and A1,A5-A6 are preserved
; Function: This routine reads the next address mark that spins by. On exit,
; the attributes of the mark are passed back as:
;
; D1 = <side> <track>
; D2 = <sector>
; D3 = <volume>
;
; The disk should be up to speed with the correct head
; selected, and interrupts should be disabled.
;
; 'Nibble must find' count may have to be tuned.
;_______________________________________________________________________
jtISMRdAddr
; When reading immediatly after a write, the drive may suppress read data for
; up to 620µsec, so we will wait at least that long for the first byte to be valid.
; We look for 3 bytes @16µsec per byte brings the total wait to 668µsec.
; There is an access to the VIA in the loop, which must synchronize with the 783khz
; clock (1.2765µsec per access), so we compute the timeout for the fastest processor
; which would be 668/1.2765 = 523 iterations, and add in another 10% for good measure
; to get 575. It doesn't hurt for it to be too big on slower processors, it would just
; take longer to get noNybErr which should never occur unless there is a hardware error.
MOVEQ #3,D3 ; try for 3 bytes
MOVE.W #575,D2 ; setup loop timeout count
MOVEQ #0,D5 ; D5 is used for offsets, so clear it
movea.l IWM,A4 ;
LEA rData(A4),A4 ;Point to rData reg
TST.B rError-rData(A4) ;clear the error register
MOVE.B #$18,wZeroes-rData(A4) ;clear the write and action bits
MOVE.B #$01,wOnes-rData(A4) ;toggle the clFIFO bit to clear out
MOVE.B #$01,wZeroes-rData(A4) ; any data in the FIFO
TST.B rError-rData(A4) ;clear the error register again
MOVE.B #$08,wOnes-rData(A4) ;turn on the action bit: GO!
MOVE.L (SP)+,DskRtnAdr ; return address
@1 _PollSCC ; poll the SCC modem port <H5>
@2 TST.B rHandshake-rData(A4); test for a nibble
DBRA D2,@3 ; if no timeout yet, see if it was valid
MOVEQ #NoNybErr,D0 ; set CCR
BRA ISMRdAddrXit
@3 BPL.S @1 ; try again if no nibble
MOVE.B (A4),D5 ; read a nibble
SUBQ.W #1,D3 ; leave D3=0
BNE.S @1 ; if we can find 3, should be ok
MOVE.W #MustFindCt,D0 ; D0 holds nibble must find count
TST.B NewIntf(A1,D1) ; new interface drive?
BEQ.S @4
MOVE.W #MustFindCt-32,D0
@4 LEA (DNib-$96),A3 ; A3 points to denibblizing table
ISMRdAddr1 MOVE.L A2,A0 ; point to our mark table
MOVEQ #3,D1 ;
@1 TST.B rHandshake-rData(A4);look for nibble
BPL.S @1 ;
MOVE.B (A4),D5 ;read the nibble
_PollSCC ; poll the SCC modem port <H5>
@2 DBRA D0,@3 ;
MOVEQ #NoAdrMkErr,D0 ; after 1500 tries report error
BRA.W ISMRdAddrXit
@3 CMP.B (A0)+,D5 ;
BNE.S ISMRdAddr1 ;
SUBQ.W #1,D1 ;
BNE.S @1 ; leave D1=0 (returns <side><track>)
; We found an address mark header so retrieve the information from the mark.
_PollSCC ; poll the SCC modem port <H5>
ISMRdAddrMk TST.B rHandshake-rData(A4); test for track number byte
BPL.S ISMRdAddrMk ;
MOVE.B (A4),D5 ; read it
MOVE.B 0(A3,D5.W),D1 ; denibblize it
MOVE.B D1,D4 ; init the checksum
ROR.W #6,D1 ; make room for 6 bits of side . . .
_PollSCC ; poll the SCC modem port <H5>
@2 TST.B rHandshake-rData(A4); test for sector number byte
BPL.S @2 ;
MOVE.B (A4),D5 ; read it
MOVEQ #0,D2 ; zero extend the sector number
MOVE.B 0(A3,D5.W),D2 ; denibblize it
EOR.B D2,D4 ; calculate the checksum
_PollSCC ; poll the SCC modem port <H5>
@3 TST.B rHandshake-rData(A4); test for side number byte
BPL.S @3 ;
MOVE.B (A4),D5 ; read it
MOVE.B 0(A3,D5.W),D1 ; denibblize it
EOR.B D1,D4 ; calculate the checksum
ROL.W #6,D1 ; D1,bits 0-11 = <side><track>
_PollSCC ; poll the SCC modem port <H5>
@4 TST.B rHandshake-rData(A4); test for volume number byte
BPL.S @4 ;
MOVE.B (A4),D5 ; read it
MOVE.B 0(A3,D5.W),D3 ; denibblize it
EOR.B D3,D4 ; calculate the checksum
_PollSCC ; poll the SCC modem port <H5>
@5 TST.B rHandshake-rData(A4); test for checksum nibble
BPL.S @5 ;
MOVE.B (A4),D5 ; read it
MOVE.B 0(A3,D5.W),D5 ; denibblize it
EOR.B D5,D4
BNE.S ISMBadCkSum ; report bad checksum
MOVEQ #1,D4 ; 2 bit slip marks
ISMRdAddrEnd
_PollSCC ; poll the SCC modem port <H5>
@1 TST.B rHandshake-rData(A4); test for first trail nibble
BPL.S @1 ;
MOVE.B (A4),D5 ; read it
CMP.B (A0)+,D5 ; trail mark ok?
BNE.S ISMNoSlip ; br if not
DBRA D4,ISMRdAddrEnd
ISMRdAddrXit
MOVE.B #$18,wZeroes-rData(A4) ;Clear the write and action bits
BRA DskRtn ; return with D0 positive, BPL for ok
ISMBadCkSum MOVEQ #BadCkSmErr,D0
BRA.S ISMRdAddrXit
ISMNoSlip MOVEQ #BadBtSlpErr,D0
BRA.S ISMRdAddrXit
eject ;
;_______________________________________________________________________
;
; Routine: jtISMRdData
; Arguments:
; A0.L (input) -- ptr to 512-byte data buffer
; A3.L (input) -- ptr to <DNib-$96> (denibblizing table)
; A4.L (input) -- rData reg pointer
; A5.L (input) -- ptr to 6522 A-reg (has head sel, wait/req)
; A6.L (input) -- ptr to SCC channel A data register
;
; D0.W (output) --
; 0 = no error
; -71 = no data mark found
; -72 = bad checksum
; -73 = bad bit slip marks
; A3-A6 are preserved
; all other registers are trashed
; Function: This routine reads the next data mark that spins by. The 524
; bytes of data are split as follows: the first 12 bytes are put
; into TagData, the remaining 512 bytes into the buffer at (A0).
; This routine denibblizes and computes the checksum on the fly,
; so it may be used for one-to-one reading.
;
; The disk should be up to speed with the correct head
; selected, and interrupts should be disabled. This routine
; should be called immediately after RdAddr for disk reads.
;
; To do:
;
; Currently (on the SCC version Macintosh), there is no time to check each
; nibble when denibblizing data nibbles for $FF mappings; this should be added
; when this routine is put in ROM or run on a faster processor.
;
; An optimization could be added for missed address marks: if the calling
; routine is after a particular sector number and already knows which track
; it is on, this routine could be modified to check for that sector in the
; byte just before the encoded data, and return immediately on no match . . .
;_______________________________________________________________________
jtISMRdData MOVE.L (SP)+,DskRtnAdr ; save return address here
MOVEQ #48,D2 ; D2 holds nibble must find count
MOVEQ #0,D3 ; clear D3 for use as an index
MOVEQ #-64,D0 ; $C0 used to mask off bits 0-5
MOVE.L #$1FE000A,D4 ; byte read counts for 2 buffers
MOVEQ #0,D5 ; init CkSumA
MOVEQ #0,D6 ; init CkSumB
MOVEQ #0,D7 ; init CkSumC
; try to find a valid header until we've timed out
; A4 points to rData in the case of SWIM2
; TST.B rError-rData(A4) ;Clear error register
; MOVE.B #$18,wZeroes-rData(A4) ;Clear write and action
; MOVE.B #$01,wOnes-rData(A4) ;Toggle clFIFO bit to clear out
; MOVE.B #$01,wZeroes-rData(A4) ;any data in the FIFO
TST.B rError-rData(A4) ;Clear the error register again
MOVE.B #$08,wOnes-rData(A4) ;Turn on the action bit: GO!
ISMRdData1 MOVE.L A1,A2 ; address of address marks
MOVEQ #3,D1
@1 TST.B rHandshake-rData(A4); test for nibble
BPL.S @1
MOVE.B (A4),D3 ; read it
_PollSCC ; poll the SCC modem port <H5>
@2 DBRA D2,@3
MOVEQ #NoDtaMkErr,D0 ; after 48 tries report error
BRA.S ISMRdAddrXit
@3 CMP.B (A2)+,D3
BNE.S ISMRdData1
SUBQ.W #1,D1
BNE.S @1 ; leave D1=0
; We found a data mark header so retrieve the information from the mark.
@4 TST.B rHandshake-rData(A4); test for encoded sector number
BPL.S @4 ;
MOVE.B (A4),D3 ; read it
LEA TagData+1,A1 ; A1 points to buffer for extra bytes
MOVE.B 0(A3,D3.W),(A1)+ ;
;_______________________________________________________________________
;
; We found the header so the actual info is about to spin by. There are 699
; nibbles followed by 3 checksum nibbles. We use a four nibble loop for the
; data nibbles . . . the first 12 bytes go into a separate buffer, then 512
; bytes are placed in the user's buffer.
;
; D7 = CkSumC A7 = stack (where poll data is pushed)
; D6 = CkSumB A6 = ptr to SCC chan A data reg
; D5 = CkSumA A5 = ptr to 6522 A-reg
; D4 = loop counters A4 = ptr to rData
; D3 = buffer A3 = ptr to denibblizing table
; D2 = buffer A2 = ptr to trail mark table
; D1 = buffer for odd bits A1 = ptr to data buffer
; D0 = $C0 mask A0 = ptr to user buffer
;_______________________________________________________________________
ISMRdData2 _PollSCC ; poll the SCC modem port <H5>
@0 TST.B rHandshake-rData(A4); test for a nibble
BPL.S ISMRdData2 ;
MOVE.B (A4),D3 ; read it
MOVE.B 0(A3,D3.W),D1 ; D1 = [00][00][A7][A6][B7][B6][C7][C6]
ROL.B #2,D1 ; D1 = [A7][A6][B7][B6][C7][C6][00][00]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [A7][A6][00][00][00][00][00][00]
@1 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @1 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D2 ; D2 = ByteA' (no time for bad nibs)
MOVE.B D7,D3 ;
ADD.B D7,D3 ; ex <- CkSumC[7]
ROL.B #1,D7 ; CkSumC' <- ROL (CkSumC)
EOR.B D7,D2 ; ByteA <- ByteA' XOR CkSumC'
MOVE.B D2,(A1)+ ; store first byte
ADDX.B D2,D5 ; CkSumA',ex <- CkSumA + ByteA + ex
ROL.B #2,D1 ; D1 = [B7][B6][C7][C6][00][00][A7][A6]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [B7][B6][00][00][00][00][00][00]
@2 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @2 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D2 ; D2 = ByteB' (no time for bad nibs)
EOR.B D5,D2 ; D2 = ByteB
MOVE.B D2,(A1)+ ; store second byte
ADDX.B D2,D6 ; CkSumB',ex <- CkSumB + ByteB + ex
ROL.B #2,D1 ; D1 = [C7][C6][0][0][A7][A6][B7][B6]
AND.B D0,D1 ; D1 = [C7][C6][0][0][0][0][0][0]
_PollSCC ; poll the SCC modem port <H5>
@3 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @3 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D1 ; D1 = ByteC' (no time for bad nibs)
EOR.B D6,D1 ; D1 = ByteC
MOVE.B D1,(A1)+ ; store third byte
ADDX.B D1,D7 ; CkSumC'' <- CkSumC' + ByteC + ex
SUBQ.W #3,D4 ; decrement counter by 3 bytes
BPL.S ISMRdData2 ; loop (careful->subq changes ex bit)
SWAP D4 ; first time thru switch counters, buffers
TST.B DskVerify ; doing a read verify?
BEQ.S ISMRdData3A ; br if not
BRA.S ISMRdVer1 ; br if so (only verify, don't read)
ISMRdData3 _PollSCC ; poll the SCC modem port <H5>
ISMRdData3A TST.B rHandshake-rData(A4); test for a nibble
BPL.S ISMRdData3 ;
MOVE.B (A4),D3 ; read it
MOVE.B 0(A3,D3.W),D1 ; D1 = [00][00][A7][A6][B7][B6][C7][C6]
ROL.B #2,D1 ; D1 = [A7][A6][B7][B6][C7][C6][00][00]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [A7][A6][00][00][00][00][00][00]
@1 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @1 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D2 ; D2 = ByteA' (no time for bad nibs)
MOVE.B D7,D3 ;
ADD.B D7,D3 ; ex <- CkSumC[7]
ROL.B #1,D7 ; CkSumC' <- ROL (CkSumC)
EOR.B D7,D2 ; ByteA <- ByteA' XOR CkSumC'
MOVE.B D2,(A0)+ ; store first byte
ADDX.B D2,D5 ; CkSumA',ex <- CkSumA + ByteA + ex
ROL.B #2,D1 ; D1 = [B7][B6][C7][C6][00][00][A7][A6]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [B7][B6][00][00][00][00][00][00]
@2 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @2 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D2 ; D2 = ByteB' (no time for bad nibs)
EOR.B D5,D2 ; D2 = ByteB
MOVE.B D2,(A0)+ ; store second byte
ADDX.B D2,D6 ; CkSumB',ex <- CkSumB + ByteB + ex
TST.W D4 ; check counter
BEQ.W ISMRdCkSum ; we are done when counter is 0
ROL.B #2,D1 ; D1 = [C7][C6][0][0][A7][A6][B7][B6]
AND.B D0,D1 ; D1 = [C7][C6][0][0][0][0][0][0]
_PollSCC ; poll the SCC modem port <H5>
@3 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @3 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D1 ; D1 = ByteC' (no time for bad nibs)
EOR.B D6,D1 ; D1 = ByteC
MOVE.B D1,(A0)+ ; store third byte
ADDX.B D1,D7 ; CkSumC'' <- CkSumC' + ByteC + ex
SUBQ.W #3,D4 ; decrement counter by 3 bytes
BRA.S ISMRdData3 ; loop (careful->subq changes ex bit)
ISMRVerify _PollSCC ; poll the SCC modem port <H5>
ISMRdVer1 TST.B rHandshake-rData(A4); test for a nibble
BPL.S ISMRVerify ;
MOVE.B (A4),D3 ; read it
MOVE.B 0(A3,D3.W),D1 ; D1 = [00][00][A7][A6][B7][B6][C7][C6]
ROL.B #2,D1 ; D1 = [A7][A6][B7][B6][C7][C6][00][00]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [A7][A6][00][00][00][00][00][00]
@1 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @1 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D2 ; D2 = ByteA' (no time for bad nibs)
MOVE.B D7,D3 ;
ADD.B D7,D3 ; ex <- CkSumC[7]
ROL.B #1,D7 ; CkSumC' <- ROL (CkSumC)
EOR.B D7,D2 ; ByteA <- ByteA' XOR CkSumC'
CMP.B (A0)+,D2 ; check first byte
BNE.S @4 ; (to RdVerErr) exit on errors
ADDX.B D2,D5 ; CkSumA',ex <- CkSumA + ByteA + ex
ROL.B #2,D1 ; D1 = [B7][B6][C7][C6][00][00][A7][A6]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [B7][B6][00][00][00][00][00][00]
@2 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @2 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D2 ; D2 = ByteB' (no time for bad nibs)
EOR.B D5,D2 ; D2 = ByteB
CMP.B (A0)+,D2 ; compare second byte
BNE.W ISMRdVerErr ; exit on errors
ADDX.B D2,D6 ; CkSumB',ex <- CkSumB + ByteB + ex
TST.W D4 ;
BEQ.S ISMRdCkSum ; we are done when counter is 0
ROL.B #2,D1 ; D1 = [C7][C6][0][0][A7][A6][B7][B6]
AND.B D0,D1 ; D1 = [C7][C6][0][0][0][0][0][0]
_PollSCC ; poll the SCC modem port <H5>
@3 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @3 ;
MOVE.B (A4),D3 ; read it
OR.B 0(A3,D3.W),D1 ; D1 = ByteC' (no time for bad nibs)
EOR.B D6,D1 ; D1 = ByteC
CMP.B (A0)+,D1 ; compare third byte
@4 BNE.S ISMRdVerErr ; exit on errors
ADDX.B D1,D7 ; CkSumC'' <- CkSumC' + ByteC + ex
SUBQ.W #3,D4 ; decrement counter by 3 bytes
BRA.S ISMRVerify ; loop (careful->subq changes ex bit)
; now read the four checksum nibbles and compare . . .
ISMRdCkSum _PollSCC ; poll the SCC modem port <H5>
@0 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @0 ;
MOVE.B (A4),D3 ; read it
MOVE.B 0(A3,D3.W),D1 ; D1 = [00][00][A7][A6][B7][B6][C7][C6]
BMI.S ISMDCkSumBad ; branch if bad nibble
ROL.B #2,D1 ; D1 = [A7][A6][B7][B6][C7][C6][00][00]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [A7][A6][00][00][00][00][00][00]
@1 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @1 ;
MOVE.B (A4),D3 ; read it
MOVE.B 0(A3,D3.W),D3 ; D3 = [0][0][A5][A4][A3][A2][A1][A0]
BMI.S ISMDCkSumBad ; br if bad nibble
OR.B D3,D2 ; D2 = CkSumA
CMP.B D2,D5 ; check against calculated value
BNE.S ISMDCkSumBad ; br if bad
ROL.B #2,D1 ; D1 = [B7][B6][C7][C6][00][00][A7][A6]
MOVE.B D1,D2 ;
AND.B D0,D2 ; D2 = [B7][B6][00][00][00][00][00][00]
@2 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @2 ;
MOVE.B (A4),D3 ; read it
MOVE.B 0(A3,D3.W),D3 ; D3 = [0][0][B5][B4][B3][B2][B1][B0]
BMI.S ISMDCkSumBad ; branch if bad nibble
OR.B D3,D2 ; D2 = CkSumB
CMP.B D2,D6 ; check against calculated value
BNE.S ISMDCkSumBad ; br if bad
ROL.B #2,D1 ; D1 = [C7][C6][00][00][A7][A6][B7][B6]
AND.B D0,D1 ; D1 = [C7][C6][00][00][00][00][00][00]
_PollSCC ; poll the SCC modem port <H5>
@3 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @3 ;
MOVE.B (A4),D3 ; read it
MOVE.B 0(A3,D3.W),D3 ; D3 = [00][00][C5][C4][C3][C2][C1][C0]
BMI.S ISMDCkSumBad ; branch if bad nibble
OR.B D3,D1 ; D1 = CkSumC
CMP.B D1,D7 ; check against calculated value
BEQ.S ISMRdSlip ;
ISMDCkSumBad
MOVEQ #BadDCkSum,D0 ; bad checksum
BRA.S ISMRdDataXit
ISMRdVerErr MOVEQ #DataVerErr,D0
BRA.S ISMRdDataXit
; finally we must read the bit slip marks before giving our stamp of approval
ISMRdSlip MOVEQ #1,D4 ; 2 bit slip marks
@1 TST.B rHandshake-rData(A4); test for a nibble
BPL.S @1 ;
MOVE.B (A4),D3 ; read it
_PollSCC ; poll the SCC modem port <H5>
@2 CMP.B (A2)+,D3 ; trail mark ok?
BNE.S ISMNoDSlip ; br if not
DBRA D4,@1
MOVEQ #0,D0 ; report success!!!
ISMRdDataXit
MOVE.B #$18,wZeroes-rData(A4) ;Clear the write and action bits
BRA DskRtn ; return with D0 positive, BPL for ok
ISMNoDSlip MOVEQ #BadDBtSlp,D0 ; bad slip nibbles is error code 3 . . .
BRA.S ISMRdDataXit
;——————————————————————————————————————————————————————————————————————————————— <H9>
;
; Routine: CheckFor32Mhz
;
; Inputs: A1 - pointer to Sony driver's variables
;
; Outputs: none
;
; Function: Checks for clock speed of 32Mhz to the SWIM2. Sets global Clock32Mhz
; to TRUE if present, FALSE otherwise. This routine is called only for
; SWIM2.
; With a 16Mhz clock, each byte will take 16µs to shift out. We write
; out 20 bytes which will take 320µs at 16Mhz and 160µs at 32Mhz. To
; allow for any skewing and overhead we compare against 240µs.
;———————————————————————————————————————————————————————————————————————————————
CheckFor32Mhz ;
MOVEM.L D0-D3/A2-A4,-(SP) ; save regs <H28>
MOVEA.L IWM,A4 ; get SWIM2 base address
MOVEA.L VIA,A2 ; get VIA base address
LEA wData(A4),A3 ; Point to write data and
LEA rHandshake(A4),A4 ; handshake registers for speed
MOVE.B #$20,wSetup-wData(A3) ; put us into MFM mode with fast clock
MOVE.B #$86,wZeroes-wData(A3) ; Ensure that no drives are enabled
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
MOVEQ #20,D0 ; set byte count
MOVE.B D0,(A3) ; Write the first two bytes
MOVE.B D0,(A3) ; to fill up the FIFO
MOVE.B vT2CH(A2),D1 ; get timer high byte <H28>
MOVE.B vT2C(A2),D3 ; and timer low byte <H28>
CMP.B vT2CH(A2),D1 ; did high byte change? <H28>
BEQ.S @0 ; -> no, we're fine <H28>
MOVEQ #0,D3 ; yes, set low byte to 0 (which will decr both) <H28>
@0 LSL.W #8,D1 ; shift it over <H28>
MOVE.B D3,D1 ; get the lower half <H28>
MOVE.B #$08,wOnes-wData(A3); Turn on the ACTION bit and go!
@1 TST.B (A4) ; Wait until there's an opening in the FIFO
BPL.S @1
MOVE.B D0,(A3) ; Write a byte
DBRA D0,@1 ; do this until byte count is exhausted
@done MOVE.B #$18,wZeroes-wData(A3) ;Clear the write and action bits
MOVE.B vT2CH(A2),D2 ; get timer high byte <H28>
MOVE.B vT2C(A2),D3 ; and timer low byte <H28>
CMP.B vT2CH(A2),D2 ; did high byte change? <H28>
BEQ.S @2 ; -> no, we're fine <H28>
MOVEQ #0,D3 ; yes, set low byte to 0 (which will decr both) <H28>
@2 LSL.W #8,D2 ; shift it over <H28>
MOVE.B D3,D2 ; get the lower half <H28>
MOVE.B vT2CH(A2),vT2CH(A2) ; re-enable timer 2 interrupts <H31>
CLR.B Clock32MHz(A1) ; assume it's -really- slow <H24>
SUB.W D2,D1 ; get total elapsed ticks
BMI.S @ReallySlow ; -> >32K delta, so it's really slow <H24>
CMP.W #nTicks*240/1000,D1 ; how many VIA ticks elapsed? (240µs is the midpoint)
SLT Clock32Mhz(A1) ; less than 240µs worth, must be 32Mhz clock
@ReallySlow MOVEM.L (SP)+,D0-D3/A2-A4 ; restore registers <H28>
RTS ; return <SM5> end