; ; File: SonyRead.a ; ; Contains: This file contains disk driver routines used to read ; sector information from twiggy diskettes. ; ; Written by: Larry Kenyon ; ; Copyright: © 1982-1992 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 12/14/92 RC Restore Pre-PDM D2 with Horror rollin ; 12/7/92 rab Roll in Horror changes. Comments follow… ;
6/19/92 CMP Patched SetUpPoll to set A6 to point to a bogus set of ; "registers" so that no SCC polling is done if there is no ; PollProc installed. This is because on DB Lite with LocalTalk ; connected to the internal serial port, we get so much poll data ; that we corrupt the heap. ;

11/14/91 SWC Converted the SCC polling code to a macro (in SonyHdr.a) so it's ; easier to overpatch. Also cleaned up comments. ; <6> 7/14/92 CSS Fixed the comment below so an exact version of this ; file could be copied into SuperMario. ; <5> 4/27/92 JSM Get rid of conditionals: hasHarpoVIA is always false, ; supportsMFM and forROM are always true. This file now has no ; conditionals. ; <4> 1/21/91 SWC Cleaned up header comments. ; <3> 9/21/90 BG Removed <2>. 040s are behaving more reliably now. ; <2> 6/18/90 CCH Added NOPs for flaky 68040's. ; <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 extra VIA accesses in read code to allow time for a new ; bit to shift in, and clear the data latch, so that a previous ; data byte doesn't get interpreted as a new byte on fast ; processors (25mhz). Changed bit number of SCC/VIA direction bit ; save in chipState. ; <2.0> 12/15/88 GGD Changed some machine based conditionals to feature based. ; Modified nibble timeout code in RdAddr to be processor speed ; independent. ; <1.1> 11/11/88 CCH Fixed Header. ; <1.0> 11/9/88 CCH Adding to EASE. ; <1.9> 9/29/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.8> 9/19/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.7> 8/16/88 GGD Changed usages of absolute VIA/SCC hardware addresses in ; SetUpPoll, to use low mem hw base addresses instead. Changed ; vBufA to vBufD for HcMac. Saved and changed VIA Buf B Direction ; bit in SetUpPoll for HcMac. ; <1.7> 8/9/88 Saved and changed VIA Buf B Direction bit in SetUpPoll for HcMac. ; <1.7> 8/5/88 GGD Changed usages of absolute VIA/SCC hardware addresses in ; SetUpPoll, to use low mem hw base addresses instead. Changed ; vBufA to vBufD for HcMac. ; <1.6> 7/15/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <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 No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.3> 5/24/88 GGD No changes to this file, entire Sony Driver is checked out and ; in as a group. ; <1.2> 5/3/88 GGD No changes, entire sony driver checked out and in as a group. ; <1.1> 4/18/88 GGD Merged in MFM support by Steve Christensen Renamed ; RdVerify to RVerify to eleminate the name conflict with the ; RdVerify equate in SysEqu.a (removes an ASM warning) ; <1.0> 2/12/88 BBM Adding file for the first time into EASE… ; 11/13/87 MSH Time-out loop in RdAddr was too short because we are so fast. ; 10/8/87 MSH Port to HcMac (Laguna). ; 11/21/86 SWC Patched RdAddr and RdData to jump to their MFM counterparts if ; we're running in MFM mode. ; 11/5/86 TJ Text cleanup ; 10/30/86 TJ Removed IWM absolute addresses. ; 6/25/86 RDC Increased no-nibble timeout for NuMac ; 11/2/85 LAK Use NewIntf instead of Sides when adjusting MustFndCnt. ; 7/29/85 RDC Changed interrupt level settings to use equates ; 7/24/85 LAK Convert back to WorkShop. ; 1/15/85 JTC convert to MDS. ; 10/26/84 LAK Patched RdAddr to compensate for missed nibbles after write ; (during erase) and increased no-nibble timeout. ; 8/18/83 LAK Addresses of AdrMks and DtaMks tables are passed thru vectors. ; 8/11/83 LAK Sets head select according to SideTrack. ; 8/4/83 LAK Added verify-only read (does it if lowmem var DskVerify is ; non-zero). ; 4/17/83 LAK Rewrote both RdAddr and RdData to incorporate SCC channel A ; polling scheme. ; 12/17/82 LAK Changed nibble "must-find" count to 1500 from 3000. ; 11/18/82 LAK Added head select setup and a search for some nibbles to avoid ; long delays on blank tracks ; title 'File: SonyRead.a' eject ;_______________________________________________________________________ ; ; Routine: RdAddr,SetUpPoll,RdAddrSetup ; 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. ;_______________________________________________________________________ BLANKS ON STRING ASIS AdrMks DC.B $D5,$AA,$96,$DE,$AA,$FF ; code-saving proc called by RdAddrSetUp and FigTrkSpeed SetUpPoll MOVE.L JSetUpPoll,-(SP) RTS BogusSCC DCB.B 6,0 ; this is the bogus SCC register set jtSetUpPoll ; TST.L PollProc ; check to see if there is a pollproc BEQ.S @1 ; -> no, point A6 to a bogus place MOVEA.L SCCRd,A6 ; get SCC read base address BRA.S @2 ; @1 LEA BogusSCC,A6 ; fake SCC base address into A6 @2 ; ADDQ.L #AData,A6 ; SCC A-reg data <1.7> MOVEA.L VIA,A5 ; get VIA base address <1.7> ADDA.W #VBufD,A5 ; 6522 disk-reg has head sel, wait/req <1.7> ORI #HiIntMask,SR ; no ints from now on! <29Jul85> MOVE.L SP,PollStack ; init PollStack at current stack level ADD.L D0,PollStack ; compensate for 1 or 2 levels RTS RdAddrSetup MOVEQ #8,D0 ; init PollStack 8 bytes down BSR.S SetUpPoll MOVEQ #RdDtaAdr,D0 ; assume side 0 BTST #3,SideTrack(A1) ; side 1? BEQ.S @1 ; br if not MOVEQ #RdDta1Adr,D0 ; set for side 1 @1 BSR AdrDisk RdAddr BSR GetDrv1 ;Get the drive offset TST.B mfmDisk(A1,D1) ;Are we in MFM mode? BMI mRdAddr ;-> yes, do the MFM version LEA AdrMks,A2 ; point to our mark table MOVE.L JRdAddr,-(SP) RTS jtRdAddr ; 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 <2.0> MOVEQ #0,D5 ; D5 is used for offsets, so clear it movea.l IWM,A4 ; <2.0> adda.w #Q6L,A4 ; A4 points to shiftreg for speed <2.0> MOVE.L (SP)+,DskRtnAdr ; return address @1 _PollSCC ; poll the SCC modem port

@2 MOVE.B (A4),D5 ; read a nibble DBRA D2,@3 ; if no timeout yet, see if it was valid MOVEQ #NoNybErr,D0 ; set CCR BRA RdAddrXit @3 BPL.S @1 ; try again if no 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? <02Nov85> BEQ.S @4 MOVE.W #MustFindCt-32,D0 @4 LEA (DNib-$96),A3 ; A3 points to denibblizing table RdAddr1 MOVE.L A2,A0 ; point to our mark table MOVEQ #3,D1 ; @1 MOVE.B (A4),D5 ; BPL.S @1 ; _PollSCC ; poll the SCC modem port

@2 DBRA D0,@3 ; MOVEQ #NoAdrMkErr,D0 ; after 1500 tries report error BRA.W RdAddrXit @3 CMP.B (A0)+,D5 ; BNE.S RdAddr1 ; 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

RdAddrMk MOVE.B (A4),D5 ; read track number byte BPL.S RdAddrMk ; 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 MOVE.B (A4),D5 ; read sector number byte BPL.S @2 ; MOVEQ #0,D2 ; zero extend the sector number <2.0> MOVE.B 0(A3,D5.W),D2 ; denibblize it EOR.B D2,D4 ; calculate the checksum _PollSCC ; poll the SCC modem port

@3 MOVE.B (A4),D5 ; read side number byte BPL.S @3 ; 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 MOVE.B (A4),D5 ; read volume number byte BPL.S @4 ; MOVE.B 0(A3,D5.W),D3 ; denibblize it EOR.B D3,D4 ; calculate the checksum _PollSCC ; poll the SCC modem port

@5 MOVE.B (A4),D5 ; read checksum nibble BPL.S @5 ; MOVE.B 0(A3,D5.W),D5 ; denibblize it EOR.B D5,D4 BNE.S BadCkSum ; report bad checksum MOVEQ #1,D4 ; 2 bit slip marks RdAddrEnd _PollSCC ; poll the SCC modem port

@1 MOVE.B (A4),D5 ; get first trail nibble <2.1> BPL.S @1 ; <2.1> CMP.B (A0)+,D5 ; trail mark ok? BNE.S NoSlip ; br if not DBRA D4,RdAddrEnd RdAddrXit BRA DskRtn ; return with D0 positive, BPL for ok BadCkSum MOVEQ #BadCkSmErr,D0 BRA.S RdAddrXit NoSlip MOVEQ #BadBtSlpErr,D0 BRA.S RdAddrXit eject ; ;_______________________________________________________________________ ; ; Routine: RdData ; Arguments: A0.L (input) -- ptr to 512-byte data buffer ; A3.L (input) -- ptr to (denibblizing table) ; A4.L (input) -- DiskQ6L 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 . . . ;_______________________________________________________________________ DtaMks DC.B $D5,$AA,$AD,$DE,$AA,$FF RdData BSR GetDrv1 ;Get the drive offset TST.B mfmDisk(A1,D1) ;Are we in MFM mode? BMI mRdData ;-> yes, do the MFM version LEA DtaMks,A1 MOVE.L JRdData,-(SP) RTS jtRdData 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 RdData1 MOVE.L A1,A2 ; address of address marks MOVEQ #3,D1 @1 MOVE.B (A4),D3 BPL.S @1 _PollSCC ; poll the SCC modem port

@2 DBRA D2,@3 MOVEQ #NoDtaMkErr,D0 ; after 48 tries report error BRA.S RdAddrXit @3 CMP.B (A2)+,D3 BNE.S RdData1 SUBQ.W #1,D1 BNE.S @1 ; leave D1=0 ; We found a data mark header so retrieve the information from the mark. @4 MOVE.B (A4),D3 ; read the encoded sector number BPL.S @4 ; 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 Q6L (IWM) ; 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 ;_______________________________________________________________________ RdData2 _PollSCC ; poll the SCC modem port

@0 MOVE.B (A4),D3 ; read a nibble BPL.S RdData2 ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @1 ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @2 ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @3 ; 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 RdData2 ; loop (careful->subq changes ex bit) SWAP D4 ; first time thru switch counters, buffers TST.B DskVerify ; doing a read verify? BEQ.S RdData3A ; br if not BRA.S RdVer1 ; br if so (only verify, don't read) RdData3 _PollSCC ; poll the SCC modem port

RdData3A MOVE.B (A4),D3 ; read a nibble BPL.S RdData3 ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @1 ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @2 ; 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 RdCkSum ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @3 ; 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 RdData3 ; loop (careful->subq changes ex bit) RVerify _PollSCC ; poll the SCC modem port

RdVer1 MOVE.B (A4),D3 ; read a nibble BPL.S RVerify ; <1.1/12feb88> 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 MOVE.B (A4),D3 ; read a nibble BPL.S @1 ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @2 ; 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 RdVerErr ; exit on errors ADDX.B D2,D6 ; CkSumB',ex <- CkSumB + ByteB + ex TST.W D4 ; BEQ.S RdCkSum ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @3 ; 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 RdVerErr ; exit on errors ADDX.B D1,D7 ; CkSumC'' <- CkSumC' + ByteC + ex SUBQ.W #3,D4 ; decrement counter by 3 bytes BRA.S RVerify ; loop (careful->subq changes ex bit) <1.1/12feb88> ; now read the four checksum nibbles and compare . . . RdCkSum _PollSCC ; poll the SCC modem port

@0 MOVE.B (A4),D3 ; read a nibble BPL.S @0 ; MOVE.B 0(A3,D3.W),D1 ; D1 = [00][00][A7][A6][B7][B6][C7][C6] BMI.S DCkSumBad ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @1 ; MOVE.B 0(A3,D3.W),D3 ; D3 = [0][0][A5][A4][A3][A2][A1][A0] BMI.S DCkSumBad ; br if bad nibble OR.B D3,D2 ; D2 = CkSumA CMP.B D2,D5 ; check against calculated value BNE.S DCkSumBad ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @2 ; MOVE.B 0(A3,D3.W),D3 ; D3 = [0][0][B5][B4][B3][B2][B1][B0] BMI.S DCkSumBad ; branch if bad nibble OR.B D3,D2 ; D2 = CkSumB CMP.B D2,D6 ; check against calculated value BNE.S DCkSumBad ; 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 MOVE.B (A4),D3 ; read a nibble BPL.S @3 ; MOVE.B 0(A3,D3.W),D3 ; D3 = [00][00][C5][C4][C3][C2][C1][C0] BMI.S DCkSumBad ; branch if bad nibble OR.B D3,D1 ; D1 = CkSumC CMP.B D1,D7 ; check against calculated value BEQ.S RdSlip ; DCkSumBad MOVEQ #BadDCkSum,D0 ; bad checksum BRA.S RdDataXit RdVerErr MOVEQ #DataVerErr,D0 BRA.S RdDataXit ; finally we must read the bit slip marks before giving our stamp of approval RdSlip MOVEQ #1,D4 ; 2 bit slip marks @1 MOVE.B (A4),D3 ; get next trail nibble BPL.S @1 ; _PollSCC ; poll the SCC modem port

@2 CMP.B (A2)+,D3 ; trail mark ok? BNE.S NoDSlip ; br if not DBRA D4,@1 MOVEQ #0,D0 ; report success!!! RdDataXit BRA DskRtn ; return with D0 positive, BPL for ok NoDSlip MOVEQ #BadDBtSlp,D0 ; bad slip nibbles is error code 3 . . . BRA.S RdDataXit ; Denibblizing Table (nibbles $96 thru $FF converted to $00 thru $3F) ; $FF means illegal nibble: if we checked for illegal nibbles (currently we ; don't have time for it), this table could be extended down to $80 . . . DNib DC.B $00,$01,$FF,$FF,$02,$03 ; $96,$97, , ,$9A,$9B DC.B $FF,$04,$05,$06,$FF,$FF ; ,$9D,$9E,$9F, , DC.B $FF,$FF,$FF,$FF,$07,$08 ; , , , ,$A6,$A7 DC.B $FF,$FF,$FF,$09,$0A,$0B ; , , ,$AB,$AC,$AD DC.B $0C,$0D,$FF,$FF,$0E,$0F ; $AE,$AF, , ,$B2,$B3 DC.B $10,$11,$12,$13,$FF,$14 ; $B4,$B5,$B6,$B7, ,$B9 DC.B $15,$16,$17,$18,$19,$1A ; $BA,$BB,$BC,$BD,$BE,$BF DC.B $FF,$FF,$FF,$FF,$FF,$FF ; , , , , , DC.B $FF,$FF,$FF,$FF,$FF,$1B ; , , , , ,$CB DC.B $FF,$1C,$1D,$1E,$FF,$FF ; ,$CD,$CE,$CF, DC.B $FF,$1F,$FF,$FF,$20,$21 ; ,$D3, , ,$D6,$D7 DC.B $FF,$22,$23,$24,$25,$26 ; ,$D9,$DA,$DB,$DC,$DD DC.B $27,$28,$FF,$FF,$FF,$FF ; $DE,$DF, DC.B $FF,$29,$2A,$2B,$FF,$2C ; ,$E5,$E6,$E7, ,$E9 DC.B $2D,$2E,$2F,$30,$31,$32 ; $EA,$EB,$EC,$ED,$EE,$EF DC.B $FF,$FF,$33,$34,$35,$36 ; , ,$F2,$F3,$F4,$F5 DC.B $37,$38,$FF,$39,$3A,$3B ; $F6,$F7, ,$F9,$FA,$FB DC.B $3C,$3D,$3E,$3F ; $FC,$FD,$FE,$FF