; ; 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): ; ; 1/10/93 RC Added nops for Smurf ; 12/14/92 RC Restore Pre-PDM D2 with Horror Roll in ; 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. ; 12/8/92 rab Removed a forROM conditional from jtISMRdData that was causing ; an 'Uncompleted conditional directive' warning. ; 12/7/92 rab Roll in Horror changes. Comments followΙ ; 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. ; 7/21/92 NJV Removed hasSonora1 conditionalized code (no longer needed) ; 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. ; 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. ;
3/6/92 CMP Increased mByteTOCnt to 60 to accomodate 33Mhz. CPUs. ;

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. ; 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 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). ; 2/5/88 SWC Fixed the gap lengths to conform with IBM standard. ; 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. ; 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)
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 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 BPL.S @2 ; -> no, done 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 endif CMP.B rPhase(A0),D0 ; must be an SWIM2 BNE.S @2 ; -> mismatch: SWIM 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 @2 ; -> mismatch: SWIM 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 @2 ; -> mismatch: SWIM SUBQ.B #1,isSWIM(A1) ; a SWIM2 is installed ST mfmMode(A1) ; make sure we always use the ISM register set LEA jtISMRdAddr,A0 ; use special SWIM2 routines for GCR reading MOVE.L A0,JRdAddr ; LEA jtISMRdData,A0 ; MOVE.L A0,JRdData ; BSR CheckFor32Mhz ; check for high speed clock to SWIM2 @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 ORI #HiIntMask,SR ; and disable interrupts MOVEA.L IWM,A0 ; CMP.B #-2,isSWIM(A1) ; see if this is a SWIM2 BEQ @2 ; 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 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 endif MOVE.B #$C0,wIWMConfig(A0) ;Set timer kill + 16MHz timer if NonSerializedIO then nop ; force write to complete endif MOVEQ #$20,D0 ;Init the Setup register to disable the ECM TST.B mfmDisk(A1,D1) ; is this an MFM disk? BMI.S @MFM ; -> yes MOVEQ #$44,D0 ; GCR setup @MFM ; CMP.B #-2,isSWIM(A1) ; SWIM2? BNE.S @7 ; -> no, setup is fine the way it is TST.B Clock32Mhz(A1) ; do we have a 32Mhz Clock? BEQ.S @7 ; -> no BSET #3,D0 ; yes, set the half speed bit @7 ; MOVE.B D0,wSetup(A0) ; write the setup register 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 ; 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

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 ; 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 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 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? BEQ.S @1 ; MOVE.B #$20,wOnes(A0) ;high BRA.S @2 ; @1 MOVE.B #$20,wZeroes(A0) ;low @2 BTST #1,D0 ;Is SEL high or low? 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) MOVE.B #$20,wZeroes(A0) ; 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 -- (low-order 12 bits) ; D2 -- ; D3 -- +$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 MOVE.B #$01,wOnes-rMark(A4) ;toggle the clFIFO bit to clear out MOVE.B #$01,wZeroes-rMark(A4) ; any data in the FIFO if NonSerializedIO then nop ; force write to complete endif BTST #5,rHandshake-rMark(A4) ; check to see if there are any errors BEQ.S @0 ; -> no, continue TST.B rError-rMark(A4) ; yes, clear the error register @0 MOVE.B #$08,wOnes-rMark(A4) ;turn on the action bit: GO! if NonSerializedIO then nop ; force write to complete endif MOVEA.L A2,A0 ;point to our mark table MOVEQ #markSize-1,D1 @1 TST.B (A5) ; throttle execution speed with a VIA access BTST #RxCA,aCtl-aData(A6) ; SCC data available? BEQ.S @2 MOVE.B (A6),-(SP) ; yes, push it on the stack @2 TST.B (A3) ;wait for an address mark byte DBMI D2,@1 BPL ReadExit ;-> timed out (return "No Address Mark") MOVE.B (A4),D5 ;get a byte CMP.B (A0)+,D5 ;is it a correct mark byte? DBNE D1,@1 BEQ.S RdAddrMarkDone ;-> yes, branch back into mainline code MOVE.B #$08,wZeroes-rMark(A4) ;-> no, clear the write and action bits BRA.S RdAddrMark ; and start over RdAddrMarkDone ; ; 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

@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 ; Try to find a valid data mark (the next mark must be a data mark or something's wrong) RdDataMarkStart ; 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 ; MOVEQ #-1,D2 ; timeout counter (needs to be tuned) MOVE.L A1,D5 ; MOVEA.L SonyVars,A1 ; CMPI.B #-2,isSWIM(A1) ; are we using a SWIM2? MOVEA.L D5,A1 ; BNE.S RdDataMark ; -> nope @Wait4Mark _PollSCC ; poll the SCC modem port
MOVE.B (A3),D5 ; wait for a data mark DBMI D2,@Wait4Mark ; BPL ReadTOErr ; -> timed out BTST #0,D5 ; is it a mark byte? BNE GotDataMark ; -> yes, go for it MOVE.B (A4),D5 ; read a garbage byte BRA.S @Wait4Mark ; -> keep trying RdDataMark _PollSCC ; poll the SCC modem port

@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 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 MOVE.B #$08,wZeroes-rMark(A4) ;-> no, clear the write and action bits if NonSerializedIO then nop ; force write to complete endif LEA mDataMarks,A1 ; reset pointer to data mark field DBRA D4,RdDataMarkStart ; start again, we will try twice BRA ReadExit ; After second try, exit with noDataMkErr @1 MOVE.W #512-1,D4 ; Initialize number of bytes to read TST.B DskVerify ; Are we comparing? 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

@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

@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 DBMI D4,@2 BPL.S ReadTOErr ;-> timeout MOVE.B (A3),D5 ;Get the handshake register with valid bits 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

@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

@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

@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

@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 TST.B rError-wData(A3) ; clear the error register again ; 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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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

@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 ;_______________________________________________________________________ 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) -- (low-order 12 bits) ; D2.W (output) -- ; D3.W (output) -- ; A3.L (output) -- ptr to (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 = ; D2 = ; D3 = ; ; 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
@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
@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 ) ; We found an address mark header so retrieve the information from the mark. _PollSCC ; poll the SCC modem port
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
@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
@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 = _PollSCC ; poll the SCC modem port
@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
@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
@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 (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
@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
@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
@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
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
@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
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
@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
@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
@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
@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 ;ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; ; 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 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 MOVE.B vT2C(A2),D3 ; and timer low byte CMP.B vT2CH(A2),D1 ; did high byte change? BEQ.S @0 ; -> no, we're fine MOVEQ #0,D3 ; yes, set low byte to 0 (which will decr both) @0 LSL.W #8,D1 ; shift it over MOVE.B D3,D1 ; get the lower half 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 MOVE.B vT2C(A2),D3 ; and timer low byte CMP.B vT2CH(A2),D2 ; did high byte change? BEQ.S @2 ; -> no, we're fine MOVEQ #0,D3 ; yes, set low byte to 0 (which will decr both) @2 LSL.W #8,D2 ; shift it over MOVE.B D3,D2 ; get the lower half MOVE.B vT2CH(A2),vT2CH(A2) ; re-enable timer 2 interrupts CLR.B Clock32MHz(A1) ; assume it's -really- slow SUB.W D2,D1 ; get total elapsed ticks BMI.S @ReallySlow ; -> >32K delta, so it's really slow 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 RTS ; return end