mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-12-01 02:51:04 +00:00
2355 lines
86 KiB
Plaintext
2355 lines
86 KiB
Plaintext
;
|
||
; 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: don’t 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
|