mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
2355 lines
85 KiB
Plaintext
2355 lines
85 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
|