mac-rom/OS/SCSIMgr/SCSIMgrHWPSC.a
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

1787 lines
66 KiB
Plaintext

;
; File: SCSIMgrHWPSC.a
;
; Contains: SCSI Manager 53c96 Hardware-Specific routines
;
; Written by: Jonathan Abilay/Paul Wolf
;
; Copyright: © 1990-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM11> 8/12/93 KW conditionalizing smurf branches
; <SM10> 8/11/93 KW added some branches based on new smurf boxes
; <SM9> 12/23/92 RC Added Support for Smurf on Wombat
; <SM8> 12/3/92 fau Added boxRiscQuadra to the previous DAFBExists change.
; <SM7> 12/3/92 fau Changed the use of DAFBExists to check for the
; Spike/Eclipse/Zydeco box flag. Those registers on DAFB are only
; needed on those machines. Changed the check for BoxCyclone to a
; TestFor PSCExists (this assumes that only Cyclone type machines
; have a PSC).
; <SM6> 11/3/92 SWC Changed SCSIEqu.a->SCSI.a.
; <SM5> 8/24/92 PN Take out CycloneboxEVT1 stuff
; <SM4> 8/9/92 CCH Modified boxflag check for Quadras to include RISC Quadras.
; <SM3> 6/21/92 RB Also check for BoxCycloneEVT1 to select the right SCSI, this is
; temporary while we need to support EVT1 units.
; <SM2> 6/2/92 CS Move Hack from <SM0> so that it will assemble.
; <1> 6/2/92 kc first checked in
; <SM0> 6/01/92 kc Rolled in from Pandora. (Hacked out DAFB stuff)
; <P2> 1/28/92 PW Added Cyclone to initialization of SCSI clock-dependent
; registers.
; <P1> 1/17/92 PDW first checked in
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; Pre-Pandora ROM comments begin here.
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; <4> 9/4/91 SAM (PDW) Fixed polled write PhaseErr bug by using status register
; for phase test instead of bogus D5 register.
; <3> 8/21/91 SAM (PDW) Removed bunch of debugging stuff. Removed "fix" for VM_On
; BEH problem since "real" fix is now in dataCommon_96
; (SCSIMgr96.a).
; <2> 8/19/91 SAM (PDW) Reverted to old in/out buserr handler support. Fixed
; incorrect loop counting in BusErrHandler (wasn't taking zero
; case into account). Increased quanta of DREQ timeout value
; in BEH (twice as long). Changed Transfer so that we don't modify
; yeOldeBusErrVct if vector at 8 is already our SCSI bus error
; handler. This fixes "symptom" of VM_On/BEHandler Vector bug.
; <1> 8/8/91 SAM (PDW) Checked into Regatta for the first time with lots of
; changes over the TERROR sources.
; <0> 8/8/91 SAM Split off from TERROR sources.
;
; Pre Regatta split-off change history:
;
; <T10> 7/8/91 djw (pdw) Fixed bug in FastRead_96 and FastComp_96 where any odd
; count over 256 bytes would fail (cmp.b should be a cmp.l).
; <T9> 6/27/91 BG (actually PDW/CCH/BG) changed the dynamic register setup stuff
; in InitSCSICyc96HW so that the ProductInfo record is where the
; information for the BoxFlag check comes from.
; <T8> 6/27/91 djw (actually PDW) Changes for better handling of select sequence
; across phases and across traps. Added NOPs at top and bottom of
; non-serialized accesses to squish pipeline (to avoid problems at
; higher CPU speeds. Fixed SlowRead hang (when phase changes
; before transfer is complete (scInc or scNoInc). Fixed FastRead
; residual byte problem (where we didn't detect the missing REQ)
; by checking the FIFO count before doing the rFFO. Also removed
; all traces of SCSIBusy and FreeHook stuff. Made BusErrHandler
; able to deal with no valid registers. (JMA) Added BusErrHandler
; routine.
; <T7> 6/14/91 djw (actually PDW) Created working Transfer_96 routine that sends
; ptr to non-serialized chip image to data routines. Also modified
; all data routines to use this for all rDMA register accesses.
; Put FCIntPend clear in WaitForSCSIIntrp_PSC (w & w/o timeout) so
; that every time the interrupt bit in the chip was cleared, this
; select_in_progress flag is cleared also.
; <T6> 6/9/91 BG (BG) InitHW_SCSI_PSC: Reworked the routine to handle dynamic
; initialization of DAFB/Turbo SCSI register based on CPU clock
; speed. Modified check for SCSI clk speed initialization for
; Eclipse and Spike to (1) be based on D2 instead of BoxFlag,
; since BoxFlag has not been initialized yet when this routine is
; called, and (2) added dynamic initialization of 16/25MHz SCSI
; clk speed based on CPU clk speed. (PDW) Changed throwaway reg
; at end. Rearranged headers to work more consistently between
; test INIT and ROM builds.
; <T5> 3/30/91 BG (actually JMA) Rolled in faster SlowRead_96 and SlowComp_96
; routines.
; <T4> 2/17/91 BG (actually JMA) Added SlowComp_96, FastComp_96 & Error calls.
; <T3> 1/11/91 BG Added fix to correctly reset SCSI 96 bus.
; <T2> 1/5/91 BG (actually JMA) Added functionalites.
; <T1> 12/7/90 JMA Checked into TERROR for the first time
;
;========================================================================== <T4>
MACHINE MC68020 ; '020-level
BLANKS ON ; assembler accepts spaces & tabs in operand field
STRING ASIS ; generate string as specified
PRINT OFF ; do not send subsequent lines to the listing file
; don't print includes
PostNOP EQU 1 ; <T8>
LOAD 'StandardEqu.d' ; from StandardEqu.a and for building ROMs
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'UniversalEqu.a' ; for VIA bit and -TestFor- definitions <T6>
INCLUDE 'SCSI.a'
INCLUDE 'SCSIPriv.a'
INCLUDE 'SCSIEqu96.a'
INCLUDE 'MC680x0.a'
PRINT ON ; do send subsequent lines to the listing files
SCSICycHW96 PROC EXPORT
EXPORT SlowRead_PSC, Transfer_PSC, Xfer1Byte_PSC
EXPORT Wt4DREQorIntPSC,HandleSelInProgPSC
EXPORT ResetBus_PSC, WaitForSCSIIntrp_PSC
EXPORT BusErrHandler_PSC ; <T8>
EXPORT InitHW_SCSI_PSC,IntHnd_SCSI_PSC
EXPORT SlowWrite_PSC, SlowComp_PSC ; <T4>
EXPORT FastRead_PSC, FastWrite_PSC, FastComp_PSC ; <T4>
IMPORT ClearSCSIInt ; from InterruptHandlers.a <T4>
IMPORT SCSIpcTo32Bit_PSC, Error_PSC, SwapMMU ; from SCSIMgr96.a <T4>
EXPORT WaitForIntNoTime_PSC
WITH scsiPB, scsiPrivPB ; access record without explicit qualification
WITH scsiGlobalRecord, dcInstr
;--------------------------------------------------------------------------
;
; InitHW_SCSI_PSC - reset and initialize the 53C96 SCSI controller
; This routine resets all functions in the chip and returns
; it to a disconnected state.
;
; INPUTS
; a3 -> pointer to SCSI port base address <T6>
; a4 -> pointer to SCSI DAFB register <T6>
; (NOTE - this routine assumes that we are in 32-bit mode!) <T6>
; d2 -> 16/HWCfgFlags, 8/BoxFlag, 8/MemDecoder <T6>
; (the lowMem BoxFlag is not yet defined!) <T6>
;
; OUTPUTS
; d0 <- rINT(a3) <T6>
;
; trashes: d0, d1, a0 <T6>
InitHW_SCSI_PSC
move.b #cRstSChp, rCMD(a3) ; load reset-scsi-chip cmd, this cmd has
; the same effect as a hw reset
move.b #cNOP, rCMD(a3) ; NOP required after HW or SW reset
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
move.b #initCF1, rCF1(a3) ; load init config. value which affects:
; busID, SCSI reset reporting & parity checking
move.b #initCF2, rCF2(a3) ; load init config. value
move.b #initCF3, rCF3(a3) ; load init config. value
; Check whether or not we're 25 or 33MHz and set SCSI bus speed values appropriately <T6> thru next <T6>
TestFor VIA2Exists ; see if we should check 25/33MHz VIA2 bit
beq.s @setupC96 ; if there's not a VIA2, don't do it.
; Change to check for BoxFlags for Spike/Eclipse/Zydeco, instead of DAFBExists, since this
; special stuff only applies to those 3 machines. <SM7>
move.l UnivInfoPtr,A0 ; get pointer to universal table
cmp.b #BoxQuadra700,ProductInfo.ProductKind(A0) ; check for a Spike
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco
cmp.b #BoxQuadra900,ProductInfo.ProductKind(A0) ; check for a Eclipse
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco
cmp.b #BoxQuadra950,ProductInfo.ProductKind(A0) ; check for a Zydeco
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco
IF forSmurf THEN
cmp.b #boxRiscQuadra700,ProductInfo.ProductKind(A0) ; check for a RISC Quadra700 <SM10>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM10>
cmp.b #boxRiscQuadra900,ProductInfo.ProductKind(A0) ; check for a RISC Quadra900 <SM10>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM10>
cmp.b #boxRiscQuadra950,ProductInfo.ProductKind(A0) ; check for a RISC Quadra950 <SM10>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM10>
cmp.b #boxRiscCentris610,ProductInfo.ProductKind(A0) ; check for a RISC Quadra610 <SM10>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM10>
cmp.b #boxRiscCentris650,ProductInfo.ProductKind(A0) ; check for a RISC Quadra650 <SM10>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM10>
cmp.b #boxRiscQuadra800,ProductInfo.ProductKind(A0) ; check for a RISC Quadra800 <SM10>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM10>
cmp.b #boxRiscQuadra610,ProductInfo.ProductKind(A0) ; check for a RISC Quadra610 <SM11>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM11>
cmp.b #boxRiscQuadra650,ProductInfo.ProductKind(A0) ; check for a RISC Quadra650 <SM11>
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM11>
ENDIF ; for smurf
bra.s @setupC96 ; only Spike/Eclipse have a VIA2 and DAFB
@DoSpikeEclipseZydeco
move.l VIA2,a0 ; and get VIA2 so that we can check the speed bit
move.b vBufB(a0),d0 ; read PBx values for 25/33MHz checks
btst #v2Speed,d0 ; are we 25 MHz or 33 Mhz?
beq.s @25MHz ; IF Speed == 33MHz THEN
move.l #tsc_cf_stg_33,(a4) ; setup DAFB SCSI config register.
; ... must move 32 bits to DAFB
bra.s @setupC96 ; ELSE // Speed == 25MHz
@25MHz
move.l #tsc_cf_stg_25,(a4) ; setup DAFB SCSI config register.
; ... must move 32 bits to DAFB
; ENDIF
@setupC96
;******* Need to work with Spike, Eclipse, Zydeco or Cyclone ***** <P2> thru next <P2>
;
; CPU SCSI
; Quadra700 25 25
; Quadra900 25 15.6672
; Zydeco 33 24.28416 (boxFlag=Eclipse)
; Cyclone 33 25 or 24.576 (which?)
move.l UnivInfoPtr,A0 ; get pointer to universal table <T9>
cmp.b #BoxQuadra700,ProductInfo.ProductKind(A0) ; check for a Spike <T9>
beq.s @ForSpike ; (note - BoxFlag is not defined at this point in boot) <T9>
IF forSmurf THEN
cmp.b #boxRiscQuadra700,ProductInfo.ProductKind(A0) ; check for a RISC Card in Quadra700 <SM10>
beq.s @ForSpike ; (note - BoxFlag is not defined at this point in boot) <SM10>
cmp.b #boxRiscCentris610,ProductInfo.ProductKind(A0) ; check for a RISC Card in Centris610 <SM10>
beq.s @ForSpike ; (note - BoxFlag is not defined at this point in boot) <SM10>
cmp.b #boxRiscCentris650,ProductInfo.ProductKind(A0) ; check for a RISC Card in a Centris650 <SM10>
beq.s @ForSpike ; (note - BoxFlag is not defined at this point in boot) <SM10>
cmp.b #boxRiscQuadra800,ProductInfo.ProductKind(A0) ; check for a RISC Card in a Quadra800 <SM10>
beq.s @ForSpike ; (note - BoxFlag is not defined at this point in boot) <SM10>
cmp.b #boxRiscQuadra610,ProductInfo.ProductKind(A0) ; check for a RISC Card in a Quadra610 <SM11>
beq.s @ForSpike ; (note - BoxFlag is not defined at this point in boot) <SM11>
cmp.b #boxRiscQuadra650,ProductInfo.ProductKind(A0) ; check for a RISC Card in a Quadra650 <SM11>
beq.s @ForSpike ; (note - BoxFlag is not defined at this point in boot) <SM11>
ENDIF ; for smurf
TestFor PSCExists ; Do we have a PSC?
bne.s @ForCyclone ; Yes, we do
; Either Eclipse or Zydeco, Check for difference between 25 and 33MHz: <T6>
btst #v2Speed,d0 ; are we running at 25 or 33 MHZ? <T6>
bne.s @ForZydeco ; IF Speed == 25MHz THEN <T6>
; Set up for a 16MHz (more or less) SCSI clock
@ForEclipse
move.b #ccf15to20MHz, rCKF(a3) ; load clock conversion factor (CCF) value
move.b #SelTO16Mhz, rSTO(a3) ; load select/reselect timeout value
bra.s @1 ; <T6>
; Set up for a 25MHz (more or less) SCSI clock
@ForZydeco ; ELSE // Speed == 33MHz <T6>
@ForSpike
@ForCyclone ; <P2> from prev <P2>
move.b #ccf20to25MHz, rCKF(a3) ; load clock conversion factor (CCF) value
move.b #SelTO25Mhz, rSTO(a3) ; load select/reselect timeout value
@1
move.b #initOp, rSYO(a3) ; select sync or async operation; if sync then
; sync offset value must be nonzero
; Set synch xfer period and offset if using
; synch data xfer
move.b rINT(a3), d0 ; read & clear rFOS, rSTA & rINT into throwaway <T6>
rts
;--------------------------------------------------------------------------
;
; IntHnd_SCSI_PSC - This is the SCSICyc96 interrupt handler
; Called by: Macintosh Interrupt Dispatcher
;
; Regrs saved: a0-a5/d0-d7
;
IntHnd_SCSI_PSC
movem.l intrRegs, -(sp) ; save registers
movea.l SCSIGlobals, a4 ; get ptr to structure
clr.l d5 ;
addq.l #1, G_IntrpCount(a4) ; count intrps - FOR Debug
move.l base539x0(a4), a3 ; load ptr for SBus0 <T2>
btst.b #bINT, rSTA(a3) ; test intrp bit of status regr
bne.s @gotSCSIInt ; bra. if we got SCSI intrp
@chkNext
move.l base539x1(a4), a3 ; load ptr for SBus1 <T2>
btst.b #bINT, rSTA(a3) ; test intrp bit of status regr
beq.s @ExitSCSIIntrp
@gotSCSIInt ;
; addq.l #1, G_base5396(a4) ; incr. valid SCSI intrp counter, for debug <T2>
move.b rSTA(a3), d5 ; read Status regr
swap d5 ;
move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr
lsl.w #8, d5 ; shift left by 1 byte
move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT
swap d5 ; d5 = rFOS|rINT|0|rSTA
move.l d5, G_IntrpStat(a4) ; save regr values, for debug <T2>
@ExitSCSIIntrp
movem.l (sp)+, intrRegs ; restore registers
rts ;
;--------------------------------------------------------------------------
; Transfer_PSC - <T7> thru next <T7>
;
; Called by: dataCommon_PSC
; (NewSCSIWBlind_PSC, NewSCSIWrite_PSC, NewSCSIRBlind_PSC, NewSCSIRead_PSC)
;
; Calls: The primitive data transfer routines
;
; Registers: d0 <-- error, if any
; d1 <-- bytes transferred
; d2 --> number of bytes to transfer
; d4 --> type of transfer to perform (offset into "dataTable")
;
; a2 --> ptr to data buffer
; a3 --> SCSI chip read base address - SERIALIZED
; a4 --> ptr to SCSI Mgr globals
;
; Function: Sets up and dispatches to the simple data-transfer routines
;
; All primitive data transfer routines called by this routine assume:
;
; d0 - <-- error (if any)
; d1 - <-- bytes transferred
; d2 - --> number of bytes to transfer
; d3 - scratch - saved
; d4 - --> type of transfer to perform
; d5 - scratch - saved
; d6 - scratch - saved
;
; a0 - scratch - saved
; a1 - SCSI chip read base address - NON-SERIALIZED
; a2 - ptr to data buffer - saved
; a3 - SCSI chip read base address - SERIALIZED
; a4 - ptr to SCSI Mgr globals
; a5 - scratch - saved
;
;
; Stack frame definitions (frame allocated in StdEntry)
;
XferFrame RECORD {LINK},DECR
returnAddr ds.l 1 ; return address
; no parameters
LINK ds.l 1 ; location of old A6 (after LINK A6)
; local variables (set up and checked in BusErrHandler)
BusErrTO ds.l 1 ; when to stop retrying bus errs
BusErrAddr ds.l 1 ; user's data address when bus err happens
linkSize EQU *
ENDR
WITH XferFrame
Transfer_PSC:
link a6, #linkSize ; allocate local storage
moveq #MaxBusErr,d0 ; upper limit for 680x0's
cmp.b #cpu68040,CpuFlag ; check if we're on an 040
bne.s @storeValue ; NO ... leave BusErrCount alone
moveq #Max040BusErrs,d0 ; YES ... use 040 MaxBusErr value
@storeValue ;
move.l #0, BusErrAddr(a6) ; init so first bus err is seen as a new one
moveq.l #noErr, d0 ; assume no error
move.l d2, d1 ; make a copy of the count - is it zero ?
beq.w @exit ; if so, get out
movem.l a1-a5/d2-d6, -(sp) ; save registers
movea.l a3,a1 ; point to serialized chip image
adda.l #nonSerlzdDisp,a1 ; point to non-serialized chip image
btst.b #OurBus, G_State96(a4) ; is c96 initiator on bus?
beq.s @phaseErr ; no - then we've got a phase error
bsr HandleSelInProgPSC ; handle unfinished select command
bne.w @phaseErr ; if it is stuck, we are not in data phase
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T8>
; move.l BusErrVct, D0 ; compare old vector (at 8) <2> <3>removed
; cmp.l jvBusErr(a4), D0 ; with my vector <2> <3>
; beq.s @1 ; if same, skip the install process <2> <3>
move.l BusErrVct,yeOldeBusErrVct(a4) ; keep old vector in low-mem <T8>
move.l jvBusErr(a4), BusErrVct ; install our BE Handler
@1
bset.b #HandleBusErrs, G_State96(a4) ; signal our bus err handler to be operative
move.w d4, transferType(a4) ; store the type of transfer (only word is worth anything)
lea.l dataTable(a4), a0 ; point to data transfer table in globals
movea.l 0(a0,d4.l), a0 ; get the routine address
jsr (a0) ; go to the appropriate routine
@done
bclr.b #HandleBusErrs, G_State96(a4) ; signal our bus err handler to be unoperative
move.l yeOldeBusErrVct(a4),BusErrVct ; restore previous Bus Error vector <T8><2>
movem.l (sp)+, a1-a5/d2-d6 ; restore these guys
tst.w d0 ; set the condition codes
@exit
unlk a6 ; release local storage
rts ; <T7> from last <T7>
@phaseErr
moveq.l #scPhaseErr, d0 ; return a phase error
moveq.l #0, d1 ; number of bytes transferred
bra.s @done ;
ENDWITH
;--------------------------------------------------------------------------
; OneByteRead/OneByteWrite - proc to transfer 1 byte <T2>
;
; d0 - <-- error (if any)
; d1 - --> copy of d2
; d1 - <-- bytes transferred
; d2 - --> number of bytes to transfer
; d3 - scratch - saved
; d4 - --> type of transfer to perform
; d5 - scratch - saved
; d6 - scratch - saved
;
; a0 - scratch - saved
; a1 - SCSI chip read base address - NON-SERIALIZED
; a2 - ptr to data buffer - saved
; a3 - SCSI chip read base address - SERIALIZED
; a4 - ptr to SCSI Mgr globals
; a5 - scratch - saved
OneByteRead ; <T2> thru next <T2>
move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers
jsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
bne.s xferErr ; bra. on xfer error
move.b rFFO(a3), (a2)+ ; xfer byte from FIFO into input buffer <T4> thru next <T4>
move.b rINT(a3), d3 ; read Intrp regr & clear rSTA, rSQS & rINT
btst.l #bDSC, d3 ; check for disconnected intrp
bne.s xferErr ; bra. on xfer error
moveq.l #noErr, d0 ; successful read op <T4>
rts
OneByteWrite
move.b (a2)+, rFFO(a3) ; preload the FIFO
move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers
jsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
bne.s xferErr ; bra. on xfer error
moveq.l #noErr, d0 ; successful write op
rts
xferErr
move.l #$F0, d6 ; load proc ID, generic transfer <T4> thru next <T4>
moveq.l #scCommErr, d0 ; transfer error
bra.s errExit
phaseErr1
move.l #$F0, d6 ; load proc ID, generic trnasfer
moveq.l #scPhaseErr, d0 ; return a phase error
errExit
jsr Error_PSC ; call Error proc - for debug
clr.l d1 ; no bytes transferred
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
rts ; <T4>
;--------------------------------------------------------------------------
; Xfer1Byte_PSC - proc to transfer 1 byte of data
;
; Branched to by SlowRead/SlowWrite(Polled) & FastRead/SlowWrite(Blind). It returns directly
; Transfer proc which call either SlowRead or FastRead.
;
; d0 - <-- error (if any)
; d1 - --> copy of d2
; d1 - <-- bytes transferred
; d2 - --> number of bytes to transfer
; d3 - scratch - saved
; d4 - --> type of transfer to perform
; d5 - scratch - saved
; d6 - scratch - saved
;
; a0 - scratch - saved
; a1 - SCSI chip read base address - NON-SERIALIZED
; a2 - ptr to data buffer - saved
; a3 - SCSI chip read base address - SERIALIZED
; a4 - ptr to SCSI Mgr globals
; a5 - scratch - saved
Xfer1Byte_PSC
move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers
jsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
rts ; IF z=1 then good xfer...
;--------------------------------------------------------------------------
; SlowRead - implements Polled Read <T2>
;
; Called by: Transfer
;
; All primitive data transfer routines assume:
;
; Inputs --->
; -> D2.L number of bytes to transfer
; -> D1.L copy of d2
; -> A1 SCSI chip read base address - NON-SERIALIZED
; -> A2 ptr to data buffer - saved
; -> A3 SCSI chip read base address - SERIALIZED
; -> A4 ptr to SCSI Mgr globals
;
; Outputs <---
; <- D0.W error (if any)
; <- D1.L bytes transferred
; <- D5.L xxxx|xxxx|xxxx|rSTA
; <- D3 scratch - saved
; <- D4
; <- D6 scratch - saved
;
; Internal ---
; A0 - scratch - saved
; A1 - SCSI chip read base address - NON-SERIALIZED
; A2 - ptr to data buffer - saved
; A3 - SCSI chip read base address - SERIALIZED
; A4 - ptr to SCSI Mgr globals
; A5 - scratch - saved
;
; Method of Data Transfer: (pDMA and programmed IO) <T5> to next <T5>
; 0) Make sure we got our intrp from the last cmd send
; 1) calculate # of 16-byte block transfers to perform using pDMA & remember the remainder
; 2) Enable c96 DMA and wait till the 16-byte FIFO is full and DREQ is asserted for the 17th byte
; 3) Transfer all data in the FIFO and wait for the intrp
; 4) Repeat until all block have been transferred
; 5) Transfer remaining data using non-DMA transfer command byte then
; Wait and poll for byte-in-fifo interrupt
; 6) Transfer data from fifo to input buffer
; 7) Repeat process until all remaining bytes have been transferred
;
GEEZ EQU 0
SlowRead_PSC
bsr HandleSelInProgPSC ; handle unfinished select command
bne.w @phaseErr ; if it is stuck, we are not in data phase
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T8>
move.l d2, d3 ; d6 = number of 64KB blocks to perform
swap d3 ; d3.w:d2.w = total#bytes to xfer
bra.s @LpReadBtm
@LpReadTop
moveq.l #iPhaseMsk, d0 ; load mask for phase bits <T4> thru next <T4>
and.b rSTA(a3), d0 ; are we in data-in phase?
cmpi.b #iDataIn, d0 ; data-in phase bits = 001
bne.w phaseErr1 ; bra. on phase err
move.b #cIOXfer, rCMD(a3) ; load non-DMA transfer cmd & begin 1 byte xfer
bsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
bne.s @xferErr ; bra. if xfer err
move.b rFFO(a3), (a2)+ ; do a byte
@LpReadBtm
dbra d2, @LpReadTop ; d2 = low word of count
dbra d3, @LpReadTop ; d3 = high word of count
@goodFRead ; d1 = # of bytes transferred
moveq.l #noErr, d0 ; successful read op
rts ;
@timedOut ; <T8>
moveq.l #scBusTOErr, d0 ; if we timed out, return error <T8>
bra.s @bytesXferd ; <T8>
@phaseErr
moveq.l #scPhaseErr, d0 ; return a phase error
bra.s @bytesXferd ; <T4>
@xferErr
moveq.l #scCommErr, d0 ; comm error
@bytesXferd ; <T4>
swap d3 ; calculate bytes left to transfer
move.w d2, d3 ; get low order word
sub.l d3, d1 ; d1 = xfer count - bytes remaining to xfer <T4> thru next <T4>
@badFRead
move.l #0, G_FakeStat(a4) ; Return a fake status
move.l #scsiRBlind, d6 ; load proc ID
jsr Error_PSC ; call Error proc - for debug
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T4>
rts ;
;--------------------------------------------------------------------------
; SlowWrite - implements Polled Write
;
; Called by: Transfer
;
; All primitive data transfer routines assume:
;
; d0 - <-- error (if any)
; d1 - --> copy of d2
; d1 - <-- bytes transferred
; d2 - --> number of bytes to transfer
; d3 - scratch - saved
; d4 - --> type of transfer to perform
; d5 - scratch - saved
; d6 - scratch - saved
;
; a0 - scratch - saved
; a1 - SCSI chip read base address - NON-SERIALIZED
; a2 - ptr to data buffer - saved
; a3 - SCSI chip read base address - SERIALIZED
; a4 - ptr to SCSI Mgr globals
; a5 - scratch - saved <T2>
;
; Method of Data Transfer: (uses pseudo-DMA mode)
; 0) Make sure we got our intrp from the last cmd send
; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max
; 2) Calc. the number of 16-byte block transfers to perform
; 3) Calc. the remaining number of transfers to perform
; 4) Write data 16-byte blocks at a time using word MOVEs
; 5) Wait without timeouts until FIFO is empty ie. 16-byte transfer completed
; 6) Transfer residual byte if there is one
;
SlowWrite_PSC
; _debugger
bsr HandleSelInProgPSC ; handle unfinished select command
bne.w @phaseErr ; if it is stuck, we are not in data phase
@doWrite
move.l d2, d3 ; d6 = number of 64KB blocks to perform
swap d3 ; d3.w:d2.w = total#bytes to xfer
bra.s @LpWriteBtm
@LpWriteTop
moveq.l #iPhaseMsk, d0 ; load mask for phase bits <T4> thru next <T4>
and.b rSTA(a3), d0 ; are we in data-in phase?
;; cmpi.b #iDataOut, d0 ; data-in phase bits = 001
bne.w phaseErr1 ; bra. on phase err
move.b (a2)+, rFFO(a3) ; write a byte
move.b #cIOXfer, rCMD(a3) ; load non-DMA transfer cmd & begin 1 byte xfer
bsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
bne.s @xferErr ; bra. if xfer err
@LpWriteBtm
dbra d2, @LpWriteTop ; d2 = low word of count
dbra d3, @LpWriteTop ; d3 = high word of count
@good ; d1 = # of bytes transferred
moveq.l #noErr, d0 ; successful read op
rts ;
@timedOut ; <T8>
moveq.l #scBusTOErr, d0 ; if we timed out, return error <T8>
bra.s @bytesXferd ; <T8>
@phaseErr
moveq.l #scPhaseErr, d0 ; return a phase error
bra.s @bytesXferd ; <T4>
@xferErr
moveq.l #scCommErr, d0 ; comm error
@bytesXferd ; <T4>
swap d3 ; calculate bytes left to transfer
move.w d2, d3 ; get low order word
sub.l d3, d1 ; d1 = xfer count - bytes remaining to xfer <T4> thru next <T4>
@badSWrite
move.l #0, G_FakeStat(a4) ; Return a fake status
move.l #scsiRBlind, d6 ; load proc ID
jsr Error_PSC ; call Error proc - for debug
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T4>
rts ;
;--------------------------------------------------------------------------
; FastWrite - implements Blind Write
;
; Called by: Transfer
;
; All primitive data transfer routines assume:
;
; d0 - <-- error (if any)
; d1 - --> copy of d2
; d1 - <-- bytes transferred
; d2 - --> number of bytes to transfer
; d3 - scratch - saved
; d4 - --> type of transfer to perform
; d5 - scratch - saved
; d6 - scratch - saved
;
; a0 - scratch - saved
; a1 - SCSI chip read base address - NON-SERIALIZED
; a2 - ptr to data buffer - saved
; a3 - SCSI chip read base address - SERIALIZED
; a4 - ptr to SCSI Mgr globals
; a5 - scratch - saved
;
; Method of Data Transfer: (uses pseudo-DMA mode)
; 0) Make sure we got our intrp from the last cmd send
; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max
; 2) Preload FIFO with non-aligned byte; get us word aligned
; 3) Calc. the number of 32-byte block transfers to perform
; 4) Calc. the remaining number of transfers to perform
; 5) Write data 32-byte blocks at a time using word MOVEs
; 6) Write remaining data using word MOVEs
; 7) Transfer residual byte if there is one
FastWrite_PSC
bsr HandleSelInProgPSC ; handle unfinished select command
bne.w @phaseErr ; if it is stuck, we are not in data phase
@doWrite
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T8>
moveq.l #iPhaseMsk, d0 ;
and.b rSTA(a3), d0 ; are we in data-out phase?
bne.w phaseErr1 ; data-out phase bits = 0, bra. on phase err <T4> thru next <T4>
cmpi.l #1, d2 ; if 1 byte write then...
beq.w OneByteWrite ; ...do 1 byte transfer
move.l d2, d6 ; d6 = number 64KB block to perform
swap d6 ; upper word of d6 = lower word of d2
andi.l #$0000FFFF, d2 ; mask out upper word
beq @2 ; if 0 then we have $10000 (64K) bytes to xfer
move.l a2, d5 ;
btst.l #0, d5 ; check if input buffer is on word boundary
bne.w @misAligned
@next64KB ; buffer is aligned from this point <T4> thru next <T4>
move.l d2, d4 ; d4 <- d2
move.b d4, rXCL(a3) ; TC regr (least-sig. byte) <- d4.b
lsr.l #8, d4 ; get upper byte of low word
move.b d4, rXCM(a3) ; TC regr (most-sig. byte) <- d4.b
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers
; DREQ* should be active at this time
move.w d2, d4 ; d4 = copy of transfer count
lsr.w #5, d4 ; divide xfer count by 32
ror.l #1, d2 ; xfer byte count to word & remember odd byte
and.w #$F, d2 ; d2 = remainder word count after 32-byte moves
neg.w d2 ; negate to form a backward jump offset
nop ; squoosh pipeline <T8>
jmp @WrLoop(d2.w*4) ; bra. into the loop <T4>
@write32 ;
move.w (a2)+, rDMA(a1) ; do 16 bytes <T7> thru next <T7>
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1) ; do another 16 bytes
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1)
move.w (a2)+, rDMA(a1) ; <T7> from last <T7>
@WrLoop
dbra d4, @write32 ; d4 = # of 32-byte tranfers <T4>
IF PostNOP THEN
nop ; squoosh pipeline <T8>
ENDIF
; INT & TC maybe TRUE at this point
btst.l #31, d2 ; check if we have a residual byte
beq.s @noResidual ;
@residual
move.b (a2)+, rDMA(a3) ; xfer residual byte <T8>
@noResidual
bsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
bne.s @xferErr ; bra. if xfer err
@2
move.l #$10000, d2 ; init to transfer 64K bytes
dbra d6, @next64KB ;
@goodFWrite ; d1 = # of bytes transferred
moveq.l #noErr, d0 ; successful write op
rts ;
@misAligned ;
subq.l #1, d2 ; adjust for transfer count calc
move.b (a2)+, rFFO(a3) ; ...preload fifo with odd byte <T4> thru next <T4>
bra.w @next64KB ; now we're word aligned
@phaseErr
moveq.l #scPhaseErr, d0 ; return a phase error
bra.s @bytesXferd ; <T4>
@xferErr
moveq.l #scCommErr, d0 ; comm error
@bytesXferd ; <T4>
swap d6 ; calculate bytes left to transfer
move.w d4, d6 ; get low order word
lsl.l #5, d6 ; multiply by 32
ext.l d2 ; make d2 a long
addq.l #1, d2 ; undo adjustment for dbra
add.l d2, d6 ; add to total
moveq.l #iFOFMsk, d2 ; <T8>
and.b rFOS(a3), d2 ; add un-xferred byte in FIFO
add.w d2, d6 ;
sub.l d6, d1 ; result
@badFWrite ; <T4> thru next <T4>
move.l #0, G_FakeStat(a4) ; Return a fake status
move.l #scsiWBlind, d6 ; load proc ID
jsr Error_PSC ; call Error proc - for debug
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T4>
rts ;
;--------------------------------------------------------------------------
; FastRead - implements FastRead
;
; Called by: Transfer
;
; All primitive data transfer routines assume:
;
; Inputs --->
; -> D2.L number of bytes to transfer
; -> D1.L copy of d2
; -> A1 SCSI chip read base address - NON-SERIALIZED
; -> A2 ptr to data buffer - saved
; -> A3 SCSI chip read base address - SERIALIZED
; -> A4 ptr to SCSI Mgr globals
;
; Outputs <---
; <- D0.W error (if any)
; <- D1.L bytes transferred
; <- D5.L xxxx|xxxx|xxxx|rSTA
; <- D3 scratch - saved
; <- D4
; <- D6 scratch - saved
;
; Internal ---
; A0 - scratch - saved
; A1 - SCSI chip read base address - NON-SERIALIZED
; A2 - ptr to data buffer - saved
; A3 - SCSI chip read base address - SERIALIZED
; A4 - ptr to SCSI Mgr globals
; A5 - scratch - saved
;
; Method of Data Transfer: (uses Pseudo-DMA)
; 0) Make sure we got our intrp from the last cmd send
; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max
; 2) Read 1st byte if input buffer is NOT word aligned
; 3) Calc. the number of 32-byte block transfers to perform
; 4) Calc. the remaining number of byte transfers to perform
; 5) Read data 32-byte blocks at a time using word MOVEs
; 6) Read remaining data a word at a time
; 7) Transfer residual byte if there is one
FastRead_PSC
bsr HandleSelInProgPSC ; handle unfinished select command
bne.w @phaseErr ; if it is stuck, we are not in data phase
@doRead
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T8>
moveq.l #iPhaseMsk, d0 ; load mask for phase bits <T4> thru next <T4>
and.b rSTA(a3), d0 ; are we in data-in phase?
cmpi.b #iDataIn, d0 ; data-in phase bits = 001
bne.w phaseErr1 ; bra. on phase err
cmpi.l #1, d2 ; special case a 1 byte transfer <T10>
beq.w OneByteRead ;
move.l d2, d6 ; d6 = number 64KB block to perform
swap d6 ; upper word of d6 = lower word of d2
andi.l #$0000FFFF, d2 ; mask out upper word
beq @2 ; if 0 then we have $10000 (64K) bytes to xfer
@next64KB
move.l d2, d4 ; d4 <- d2
move.b d4, rXCL(a3) ; TC regr (least-sig. byte) <- d4.b
lsr.l #8, d4 ; get upper byte of low word
move.b d4, rXCM(a3) ; TC regr (most-sig. byte) <- d4.b <T4>
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers
; DREQ* should be active at this time
; move.l a2, d5 ;
; btst.l #0, d5 ; check if input buffer is on word boundary
; bne.s @misAligned
@aligned
move.w d2, d4 ; d4 = copy of transfer count
lsr.w #5, d4 ; divide xfer count by 32 <T4> thru next <T4>
ror.l #1, d2 ; xfer byte count to word & remember odd byte
and.w #$F, d2 ; d2 = remainder word count after 32-byte moves
neg.w d2 ; negate to form a backward jump offset
nop ; squoosh pipeline <T8>
jmp @RdLoop(d2.w*4) ; bra. into the loop <T4>
@read32 ;
move.w rDMA(a1), (a2)+ ; do 16 bytes <T7> thru next <T7>
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+ ; do another 16 bytes
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+
move.w rDMA(a1), (a2)+ ; <T7> from last <T7>
@RdLoop ; <T4> thru next <T4>
dbra d4, @read32 ; d4 = # of 32-byte transfers
IF PostNOP THEN
nop ; squoosh pipeline <T8>
ENDIF
; INT & TC bits should be TRUE at this point
bsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
bne.s @xferErr ; bra. if xfer err
btst.l #31, d2 ; check if we have a residual byte
beq.s @2 ; bra. if no residual
@residual
bsr WtForFIFOData ; returns number of bytes in FIFO <T8>
beq.s @timedOut ; <T8>
move.b rFFO(a3), (a2)+ ; xfer residual byte
@2
move.l #$10000, d2 ; init to transfer 64K bytes <T4>
dbra d6, @next64KB ;
@goodFRead ; d1 = # of bytes transferred
moveq.l #noErr, d0 ; successful read op
rts ;
@misAligned
subq.l #1, d2 ; decr. for DBRA <T4> thru next <T4>
move.b rFFO(a3), (a2)+ ; xfer byte from fifo into input buffer
bra.s @aligned ; transfer the rest of data
@timedOut ; <T8>
moveq.l #scBusTOErr, d0 ; if we timed out, return error <T8>
bra.s @bytesXferd ; <T8>
@phaseErr
moveq.l #scPhaseErr, d0 ; return a phase error
bra.s @bytesXferd ; <T4>
@xferErr
moveq.l #scCommErr, d0 ; comm error
@bytesXferd ; <T4>
swap d6 ; calculate bytes left to transfer
move.w d4, d6 ; get low order word
lsl.l #5, d6 ; multiply by 32
ext.l d2 ; make d2 a long
addq.l #1, d2 ; undo adjustment for dbra
add.l d2, d6 ; add to total
sub.l d6, d1 ; d1 = xfer count - bytes remaining to xfer <T4> thru next <T4>
@badFRead
move.l #0, G_FakeStat(a4) ; Return a fake status
move.l #scsiRBlind, d6 ; load proc ID
jsr Error_PSC ; call Error proc - for debug
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T4>
rts ;
;-------------------------------------------------------------------------- <T8> to next <T8>
;
; WtForFIFOData - wait for 256mS for the data to show up in the FIFO
;
; a3 -> SCSI chip read base address - SERIALIZED
; d0 <- number of bytes in FIFO (zero if timed out)
; Z <- .eq.=timed out .ne.=bytes available
;
WtForFIFOData
movem.l d1-d2, -(sp)
move.w TimeSCSIDB, d1 ; get # of DBRAs
lsl.l #8, d1 ; multiply by 256
move.l d1, d2 ; ...a 256mS wait
swap d2
@1
moveq.l #iFOFMsk, d0
and.b rFOS(a3), d0 ; read FIFO flags regr
dbne d1, @1 ; loop until data or timeout
dbne d2, @1 ;
movem.l (sp)+,d1-d2
rts ; <T8> from prev <T8>
;--------------------------------------------------------------------------
;
; ResetBus - Reset the SCSI bus by asserting the SCSI Reset Output signal
; for some number of uS as determined by the clock conv. factor (CCF)
;
; a3 - SCSI chip read base address - SERIALIZED
;
ResetBus_PSC
; disable all intrps
move.b #cRstSBus, rCMD(a3) ; load reset scsi bus cmd <T3>
; re-enable all intrps
rts
;--------------------------------------------------------------------------
;
; WaitForIntNoTime_PSC - infinite loop to wait for a SCSI intrp.
;
; Uses: d0, d5
;
; On exit: d5 = rFOS|rINT|0|rSTA, byte values from the Seq.Step, Status & INT regrs. <T2>
;
; CCR.z = 1, means successful wait
; CCR.z = 0, means failed due to disconnect or lack of bus service req.
WaitForIntNoTime_PSC
@noTimeoutWait
clr.l d5 ;
move.b rSTA(a3), d5 ; read Status regr
btst.l #bINT, d5 ; poll intrp on status regr. for pending intrp
beq.s @noTimeoutWait ; ...loop until intrp req is detected
swap d5 ;
move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr
lsl.w #8, d5 ; shift left by 1 byte
move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT
move.l d5, d0 ; we got here because of an intrp
swap d5 ; d5 = rFOS|rINT|0|rSTA <T2>
andi.b #iDcBsMsk, d0 ; get Disconnect & Bus Service bits
cmpi.b #iDcBsOK, d0 ; expecting: not disconnected
; & target request info xfer phase
rts ; d5 = rFOS|rINT|0|rSTA <T4> thru next <T4>
;--------------------------------------------------------------------------
;
; HandleSelInProgPSC
;
; 0 if no select in progress or if select is now complete
; 1 if a select is still in progress (i.e. in cmd or msg_out phase)
;
HandleSelInProgPSC
btst.b #SelInProg, G_State96(a4) ; is Select cmd still in progress?
beq.w @skipIt ; no - skip it
btst.b #NeedMsgOut, G_State96(a4) ; are we expecting a Msg_Out phase?
beq.s @chkCmd ; no - see about Command
move.b #iMsgOut, d1 ; yes - wait for this phase or interrupt
bra.s @doWait
@chkCmd
btst.b #NeedCmdSent, G_State96(a4) ; are we expecting a Command phase?
beq.s @wtForFC ; no - wait for an interrupt then
move.b #iCommand, d1 ; yes - wait for this phase or interrupt
@doWait
bsr.s Wt4DREQorIntPSC
bne.s @gotDREQ
@gotInt
bclr.b #FCIntPend, G_State96(a4) ; clear the FC Int pend flag <T8>
bclr.b #SelInProg, G_State96(a4) ; and clear the SelectInProgress flag <T8>
bclr.b #NeedMsgOut, G_State96(a4) ; and Message_Out <T9>
bclr.b #NeedCmdSent, G_State96(a4) ; and Command expected flags <T9>
tst.b d0 ; setup result again
@gotDREQ
@skipIt
rts
@wtForFC
bsr.w WaitForIntNoTime_PSC
moveq.l #0, d0
bra.s @gotInt
;--------------------------------------------------------------------------
;
; Wt4DREQorIntPSC - infinite loop to wait for a DREQ signal or SCSI chip intrp.
;
; Uses: d3, d5
;
; Entry:
; --> d1 = phase to wait for (concurrent with DREQ)
;
; --> G_SCSIDREQ(a4) = addr of DAFB reg (for reading value of
;
; Exit:
; <-- d5 = rFOS|rINT|0|rSTA, byte values from the Seq.Step, Status & INT regrs.
; <-- d0 = 1 if DREQ, 0 if Int
;
;-----------------
HackOutDafb equ 1 ; Moved here because of local labels <SM2> <SM0>
Wt4DREQorIntPSC
jsr SCSIpcTo32Bit_PSC ; clean up PC first
; Check for interrupt first (to avoid unnecessary dog-slow DREQ check)
@noTimeout
clr.l d5 ;
move.b rSTA(a3), d5 ; read Status regr
btst.l #bINT, d5 ; poll intrp on status regr. for pending intrp
bne.s @gotInt ;
IF HackOutDafb THEN
bra.s @noTimeout
ELSE
; If no Interrupt, check for DREQ (go into and out of 32-bit mode to check)
; into 32-bit mode
moveq #true32B, d0 ; switch to 32-bit mode to look at SCSI config regr
jsr SwapMMU ; do it, puts previous mode in D0
move.l G_SCSIDREQ(a4), a0 ; G_SCSIDREQ contains DREQ regr address
move.l (a0), d5 ; read DAFB regr
; out of 32-bit mode (return to previous mode - already in D0)
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
; DREQ?
btst.l #bDREQ, d5 ; do we have an active DREQ from c96
beq.s @noTimeout ; no: try again
ENDIF
@gotDREQ
move.b rSTA(a3), d3 ; get phase value <T9> to next <T9>
and.b #iPhaseMsk, d3 ; load mask bits for phase value
cmp.b d3, d1 ; are we in requested phase?
bne.s @noTimeout ;
moveq.l #1, d3 ; return value = Got DREQ
bra.s @exit
; Get sequence and FIFO status registers into D5 (already got rSTA)
@gotInt
swap d5 ;
move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr
lsl.w #8, d5 ; shift left by 1 byte
move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT
move.l d5, d0 ; we got here because of an intrp
swap d5 ; d5 = rFOS|rINT|0|rSTA
moveq.l #0, d3 ; return value = Got Interrup
@exit
move.l d3, d0
rts ;
;--------------------------------------------------------------------------
;
; WaitForSCSIIntrp_PSC
;
; Proc to wait for the SCSI interrupt with a 256mS watchdog timer.
;
; Uses: d0, d3, d5
;
; On exit: d5 = rFOS|rINT|0|rSTA, byte values from the Seq.Step,
; Status & INT regrs.
; ccr.z = 1, means timedOut
WaitForSCSIIntrp_PSC
clr.l d5
moveq.l #0, d3 ; clear upper word
move.w TimeSCSIDB, d3 ; get # of DBRAs
lsl.l #8, d3 ; multiply by 256
move.l d3, d0 ; ...a 256mS wait
swap d0
@1
move.b rSTA(a3), d5 ; read Status regr
btst.l #bINT, d5 ; check for c96 INTRP
dbne d3, @1 ; loop until INT is active or timeout
dbne d0, @1 ; loop until INT is active or timeout
beq.s @timedOut ;
swap d5
move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr
lsl.w #8, d5 ; shift left by 1 byte
move.b rINT(a3), d5 ; read & clear rFOS, rSTA & rINT
@exit2
swap d5 ;
btst.l #bINT, d5 ; set condition bits
rts ; d5 = rFOS|rINT|0|rSTA
@timedOut
swap d5
move.b rFOS(a3), d5 ; read FIFO flag/Sequence Step regr
lsl.w #8, d5 ; shift left by 1 byte
move.b #0, d5 ; clear rINT value
bra.s @exit2 ;
;--------------------------------------------------------------------------
; FastCompare - implements FastRead
;
; Called by: Transfer
;
; All primitive data transfer routines assume:
;
; d0 - <-- error (if any)
; d1 - --> copy of d2
; d1 - <-- bytes transferred
; d2 - --> number of bytes to transfer
; d3 - scratch - saved
; d4 - --> type of transfer to perform
; d5 - <-- xxxx|xxxx|xxxx|rSTA
; d6 - scratch - saved
;
; a0 - scratch - saved
; a1 - SCSI chip read base address - NON-SERIALIZED
; a2 - ptr to data buffer - saved
; a3 - SCSI chip read base address - SERIALIZED
; a4 - ptr to SCSI Mgr globals
; a5 - scratch - saved
;
; Method of Data Transfer: (uses Pseudo-DMA)
; 0) Make sure we got our intrp from the last cmd send
; 1) Parcel transfer into 64KB blocks since TC regr. handles 64KB max
; 2) Read 1st byte if input buffer is NOT word aligned
; 3) Calc. the number of 32-byte block transfers to perform
; 4) Calc. the remaining number of byte transfers to perform
; 5) Read data 32-byte blocks at a time using word MOVEs
; 6) Read remaining data a word at a time
; 7) Transfer residual byte if there is one
FastComp_PSC
bsr HandleSelInProgPSC ; handle unfinished select command
bne.w @phaseErr ; if it is stuck, we are not in data phase
@doRead
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T8>
moveq.l #iPhaseMsk, d0 ; load mask for phase bits <T4> thru next <T4>
and.b rSTA(a3), d0 ; are we in data-in phase?
cmpi.b #iDataIn, d0 ; data-in phase bits = 001
bne.w phaseErr1 ; bra. on phase err
cmpi.l #1, d2 ; special case a 1 byte compare <T10>
beq.w SlowComp_PSC ; <T5>
clr.l d3 ; init compare status
move.l d2, d6 ; d6 = number 64KB block to perform
swap d6 ; upper word of d6 = lower word of d2
andi.l #$0000FFFF, d2 ; mask out upper word
beq.s @2 ; if 0 then we have $10000 (64K) bytes to xfer
@next64KB
move.l d2, d4 ; d4 <- d2
move.b d4, rXCL(a3) ; TC regr (least-sig. byte) <- d4.b
lsr.l #8, d4 ; get upper byte of low word
move.b d4, rXCM(a3) ; TC regr (most-sig. byte) <- d4.b
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers
; DREQ* should be active at this time
ror.l #1, d2 ; xfer byte count to word & remember odd byte
moveq.l #0, D0 ; clear Z (so dbne doesn't fall thru)
bra.s @RdLpBtm
@RdAndCmp
move.w rDMA(a3), d0 ; <T8>
cmp.w (a2)+, d0 ; compare a word at a time
@RdLpBtm
dbne d2, @RdAndCmp ; loop until done
beq.s @Ok
moveq.l #scCompareErr, d3 ; record a compare error
moveq.l #0, D0 ; clear Z (so dbne doesn't fall thru)
bra.s @RdLpBtm
@Ok
; INT & TC bits should be TRUE at this point
bsr.w WaitForIntNoTime_PSC ; Wait for intrp w/o timeout
; on exit d5 = rFOS|rINT|0|rSTA
bne.s @xferErr ; bra. if xfer err
btst.l #31, d2 ; check if we have a residual byte
beq.s @2 ; bra. if no residual
@residual
bsr WtForFIFOData ; returns number of bytes in FIFO <T8>
beq.s @timedOut ; <T8>
move.b rFFO(a3), D0 ; xfer residual byte
cmp.b (A2)+, D0 ; displace A2 by byte (ignore the result)
@2
move.l #$10000, d2 ; init to transfer 64K bytes
dbra d6, @next64KB ;
@ExitFCmp ; d1 = # of bytes transferred
move.l d3, d0 ; return status
rts ;
@timedOut ; <T8>
moveq.l #scBusTOErr, d0 ; if we timed out, return error <T8>
bra.s @bytesXferd ; <T8>
@phaseErr
moveq.l #scPhaseErr, d0 ; return a phase error
bra.s @bytesXferd
@xferErr
moveq.l #scCommErr, d0 ; comm error
@bytesXferd
swap d6 ; calculate bytes left to transfer
move.w d4, d6 ; get low order word
lsl.l #5, d6 ; multiply by 32
ext.l d2 ; make d2 a long
addq.l #1, d2 ; undo adjustment for dbra
add.l d2, d6 ; add to total
sub.l d6, d1 ; d1 = xfer count - bytes remaining to xfer
@badFRead
move.l #0, G_FakeStat(a4) ; Return a fake status
move.l #scsiRBlind+$F0, d6 ; load proc ID, Fast compare
jsr Error_PSC ; call Error proc - for debug
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
rts ;
;--------------------------------------------------------------------------
; SlowComp - implements Polled Read
;
; Called by: Transfer
;
; All primitive data transfer routines assume:
;
; d0 - <-- error (if any)
; d1 - --> copy of d2
; d1 - <-- bytes transferred
; d2 - --> number of bytes to transfer
; d3 - scratch - saved
; d4 - --> type of transfer to perform
; d5 - scratch - saved
; d6 - scratch - saved
;
; a0 - scratch - saved
; a1 - SCSI chip read base address - NON-SERIALIZED
; a2 - ptr to data buffer - saved
; a3 - SCSI chip read base address - SERIALIZED
; a4 - ptr to SCSI Mgr globals
; a5 - scratch - saved
;
; Method of Data Transfer: (pDMA and programmed IO) <T5> to next <T5>
; 0) Make sure we got our intrp from the last cmd send
; 1) calculate # of 16-byte block transfers to perform using pDMA & remember the remainder
; 2) Enable c96 DMA and wait till the 16-byte FIFO is full and DREQ is asserted for the 17th byte
; 3) Transfer all data in the FIFO and wait for the intrp
; 4) Repeat until all block have been transferred
; 5) Transfer remaining data using non-DMA transfer command byte then
; Wait and poll for byte-in-fifo interrupt
; 6) Transfer data from fifo to input buffer
; 7) Repeat process until all remaining bytes have been transferred
SlowComp_PSC
bsr HandleSelInProgPSC ; handle unfinished select command
bne.w @phaseErr ; if it is stuck, we are not in data phase
@doRead
moveq.l #iPhaseMsk, d0 ; load mask for phase bits
and.b rSTA(a3), d0 ; are we in data-in phase?
cmpi #iDataIn, d0 ; data-in phase bits = 001
bne.w phaseErr1 ; bra. on phase err
clr.l d3 ; init compare status
move.l d2, d4 ; d4 = copy of transfer count
lsr.l #4, d4 ; divide xfer count by 16
beq.w @16orLess ; bra. if < 16 bytes
subq.l #1, d4 ; adjust for DBRA
move.l d4, d6 ; d4.w has lower 16-byte block count
swap d6 ; d6.w has upper 16-byte word count
@16orMore
; The next few lines are necessary in order to poll DREQ in nuBus
; address space. We don't need to do this if we're xferring <16 bytes.
jsr SCSIpcTo32Bit_PSC ; use pc relative
move.b MMU32Bit, -(sp) ; save current mode on stack
moveq #true32B, d0 ; switch to 32-bit mode to look at SCSI config regr
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
move.l a2, d0 ; get destination addr in d0
_StripAddress ; clear upper byte if necessary
move.l d0, a2 ; a2 = clean buffer ptr
move.l G_SCSIDREQ(a4), a0 ; load SCSI DREQ regr
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T8>
move.b #0, rXCM(a3) ; rXCM = 0, clear most-sig. byte count
move.b #$10, rXCL(a3) ; rXCL = 16 bytes, least-sig. byte value
and.l #$F, d2 ; d2 = remainder word count after 16-byte moves
@read16
moveq.l #iPhaseMsk, d5 ; load mask bits for phase value
and.b rSTA(a3), d5 ; are we still in data-in phase?
cmpi.b #iDataIn, d5 ; data-in phase bits = 001
bne.w @premature2 ; no: probably in status phase - split
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & start loading FIFO
nop ; currently loaded transfer count is used/reused
@1
btst.b #bTRC, rSTA(a3) ; check if we've rcvd all the data <T8> thru next <T8>
bne.s @4 ; if we have, go get the bytes
btst.b #bINT, rSTA(a3) ; poll for unexpected intrp while waiting
bne.w @prematureEnd ; ... maybe disconnected or something catastrophic.
; premature phase change won't generate intrp bit 'cuz of outstanding DREQ...
; ... we have to check this condition explicitly
moveq.l #iPhaseMsk, d5 ; load mask bits for phase value
and.b rSTA(a3), d5 ; are we still in data-in phase?
cmpi.b #iDataIn, d5 ; data-in phase bits = 001
beq.s @1 ; yes, bra. & keep polling
tst.b rXCL(a3) ; not data-in anymore, have we xferred all data (XCL = 0)?
beq.s @1 ; if yes then there MUST be a transfer count zero bit set
bra.w @prematureEnd ; transfer count not 0 so we have a premature end <T8> from prev <T8>
; We need 16 guaranteed DREQs to safely transfer 16 bytes without bus error.
; Ideally, DREQ should be active as long there are threshold number of bytes in the
; FIFO--as the c96 user's guide imply. But the c96 implementation also requires that
; REQ be active in order to get DREQ. This is why we must wait for the 17th REQ from
; the target--and it must remain active--before we proceed with the 16-byte transfer.
@4
move.l (a0), d5 ; read DAFB SCSI DREQ
btst.l #bDREQ, d5 ; poll for DREQ
beq.s @1 ; loop until asserted
btst #4, rFOS(a3) ; see if FIFO is full
beq.s @1 ; loop until asserted
move.w #$7, d5 ; load loop counter, 8 words
@cmpFFO
move.w rDMA(a3), d0 ; <T8>
cmp.w (a2)+, d0 ; compare a word at a time
@cmpLp
dbne d5, @cmpFFO ; continue with compare operation
beq.s @Ok1
moveq.l #scCompareErr, d3 ; record a compare error
moveq.l #0, D0 ; clear Z (so dbne doesn't fall thru)
bra.s @cmpLp
@Ok1
; Note that intrp is asserted only after transfer count is 0, FIFO is empty
; and the target asserts REQ for the next byte.
@2
btst.b #bINT, rSTA(a3) ; check for c96 INTRP
beq.s @2 ; loop until we get the intrp
move.b rINT(a3), d5 ; read Intrp regr & clear rSTA, rSQS & rINT
btst.l #bDSC, d5 ; check for disconnected intrp
bne.s @premature2 ; Branch if transfer error
dbra d4, @read16 ; loop until done, d4 is lower word count
dbra d6, @read16 ; loop until done, d6 is upper word count
move.b (sp)+, d0 ; switch to previous address mode
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
bra.s @16OrLess ; take care of remaining data, if any
@rdSingle ; use non-pDMA for remainder
moveq.l #iPhaseMsk, d5 ; load mask bits for phase value
and.b rSTA(a3), d5 ; are we still in data-in phase?
cmpi.b #iDataIn, d5 ; data-in phase bits = 001
bne.s @phaseErr ; bra. on phase err
move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers
@3
btst.b #bINT, rSTA(a3) ; check for c96 INTRP
beq.s @3 ; loop until we get an intrp
move.b rFFO(a3), d0 ; read byte data from FIFO
cmp.b (a2)+, d0 ; xfer byte from FIFO into input buffer
beq.s @Ok2
moveq.l #scCompareErr, d3 ; record a compare error
@Ok2
move.b rINT(a3), d5 ; read Intrp regr & clear rSTA, rSQS & rINT
btst.l #bDSC, d5 ; check for disconnected intrp
bne.s @xferErr ; Branch if transfer error
@16OrLess
dbra d2, @rdSingle ; read the rest of the remainders
@ExitCmp ; d1 = # of bytes transferred
move.l d3, d0 ; return status
rts ;
; Premature phase change - get leftover bytes out of FIFO, clear DREQ and INTRPT <T8> to next <T8>
@prematureEnd
moveq.l #iFOFMsk, d0 ; use mask to get FIFO flag field
and.b rFOS(a3), d0 ; how many bytes left in FIFO?
bra.s @btmLeftovers
@topLeftovers
move.b rFFO(a3), d5
cmp.w (a2)+, d5 ; compare a word at a time - ignore result
@btmLeftovers
dbra d0,@topLeftovers
@removeDREQ
move.l (a0), d5 ; read DAFB SCSI DREQ
btst.l #bDREQ, d5 ; poll for DREQ - just to be sure
beq.s @5 ; if no DREQ, skip dummy rDMA access
move.w rDMA(a3), d5 ; remove that outstanding DREQ (magic),
bra @removeDREQ ; and see if there's more (more magic)
@5 ; and give us that intrp
bsr.w WaitForIntNoTime_PSC ; Clear pending intrp & get err status
; on exit d5 = rFOS|rINT|0|rSTA
; Premature phase change with no leftover bytes
@premature2
move.b (sp)+, d0 ; switch to previous address mode
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
; calc how many bytes we've xferred...
addq.w #1, d4 ; undo adjustment for dbra
swap d6 ; calculate bytes left to transfer
move.w d4, d6 ; form long word count
lsl.l #4, d6 ; mult by 16
and.b #iPhaseMsk, d5 ; are we still in data-in phase?
cmpi.b #iDataIn, d5 ; data-in phase bits = 001
beq.s @xferErr ; bra. to check for disconnect
@phaseErr
moveq.l #scPhaseErr, d0 ; return a phase error
bra.s @badSCmp ;
@xferErr ; anything else is a comm. err
moveq.l #scCommErr, d0 ; transfer error
@badSCmp
add.l d2, d6 ; add un-xferred remainder
sub.l d6, d1 ; number of bytes transferred
move.l #scsiRead+$F0, d6 ; load proc ID, Slow compare
jsr Error_PSC ; call Error proc - for debug
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
rts ; <T5>
;___________________________________________________________________________ <T8> to next <T8>
;
; BusErrHandler_PSC
; When the SCSI Mgr is performing a blind data transfer, it patches
; out the bus error vector. The old SCSI Mgr bus error handler
; assumed that if it got called, it must be handling a SCSI bus error.
; Unfortunately, NuBus cards could bus error while the SCSI Mgr is
; installed. To be a better bus error citizen, the SCSI bus error
; handler now checks that the fault address is the SCSI chip, and if
; not, it chains to the bus error handler that it replaced.
;
; This code returns control to Transfer_PSC and not to the routine
; caused the bus error. It does this by popping off the buserr stack
; frame and then doing an RTS, so...
; DON'T PUT ANYTHING ON THE STACK IN TRANSFER ROUTINES (FastRead,
; FastÉ, etc.). At least don't leave it there during periods where a
; buserr may be possible.
;
___________________________________________________________________________;
WITH AEXFrame, XferFrame
savedRegs REG D0-D2/A0-A1 ; save these registers because we need to use them
savedRSize EQU 5*4 ; # bytes on stack for saved registers
BusErrHandler_PSC
; Is it our fault? -----
subq.l #4, sp ; make room for return addr (@notSCSIFault)
movem.l savedRegs, -(sp)
lea savedRSize+4(sp), A0 ; make A0 our AEXFrame pointer (regs+1 LW on stack)
cmp.l SCSIGlobals, A4 ; equal if this is from our transfer routine
bne.s @notSCSIFault
btst.b #HandleBusErrs, G_State96(A4) ; are we supposed to be active?
beq.s @notSCSIFault ; no - not SCSI's fault
move.l SCSIBase, D0 ; check if bus err on SCSI Bus0 address
addi.l #rDMA, D0 ; add pseudo-DMA offset
cmp.l FaultAddr(A0), D0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
addi.l #nonSerlzdDisp, D0 ; add non-serialized offset
cmp.l FaultAddr(A0), D0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
move.l SCSI2Base, D0 ; check if bus err on SCSI Bus1 address
addi.l #rDMA, D0 ; add pseudo-DMA offset
cmp.l FaultAddr(A0), D0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
addi.l #nonSerlzdDisp, D0 ; add non-serialized offset
cmp.l FaultAddr(A0), D0 ; compare with faulted address
beq.s @SCSIFault ; if so, start processing the bus error
; It's not our fault ------
@notSCSIFault
move.l SCSIGlobals, A0 ; put entry point to prev BEH on stack
move.l yeOldeBusErrVct(A0), savedRSize(sp) ; (registers saved beneath return addr)
movem.l (sp)+, savedRegs ; restore regs
rts ; jump to old handler, assuming it'll RTE
; It's all our fault (blame it on us) ------
@SCSIFault
; Clean up the writebacks on the stack frame
move.w WB3S(A0), D0 ; check WB3 for validity
move.l WB3A(A0), A1 ; pass WB Address
move.l WB3D(A0), D1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
move.w WB2S(A0), D0 ; check WB2 for validity
move.l WB2A(A0), A1 ; pass WB Address
move.l WB2D(A0), D1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
move.w WB1S(A0), D0 ; check WB1 for validity
move.l WB1A(A0), A1 ; pass WB Address
move.l WB1D(A0), D1 ; pass WB Data
bsr.w DoWriteBack ; to routine that takes care of it
; ; old timed routine (using Ticks instead of TimeSCSIDB)
; cmp.l BusErrAddr(A6), A2 ; did we buserr at this point in the xfer b4?
; beq.s @oldBusErr
;@newBusErr
; move.l A2, BusErrAddr(A6) ; remember point in xfer that we got buserr
; move.l blindBusTO(A4), D0 ; init BusErrTO withÉ
; add.l Ticks, D0 ; BlindBusTO+Ticks
; move.l D0, BusErrTO(A6)
;@oldBusErr
; Wait for either DREQ, or INT or a timeout (from blindBusTO value)
jsr SCSIpcTo32Bit_PSC ; use pc relative
moveq #true32B, D0 ; switch to 32-bit mode to look at SCSI config regr
jsr SwapMMU ; (sets up d0 with previous mode)
move.w D0, -(sp) ; save D0 (contains previous MMU mode)
move.l G_SCSIDREQ(A4), A1 ; G_SCSIDREQ contains DREQ regr address
move.l (A1), D0 ; read DAFB regr
btst.l #bDREQ, D0 ; check for active SCSI DREQ
bne.s @retry
move.l blindBusTO(A4), D1
bra.s @outerbtm ; bra to bottom of loop for zero case <2>
@outerTop
move.w TimeSCSIDB, D2
lsr.w #1, D2 ; divide by 2 (because of 5 instr'ns instead of 2) <2>
@1
move.l (A1), D0 ; read DAFB regr
btst.l #bDREQ, D0 ; check for active SCSI DREQ
bne.s @retry
btst #bINT, rSTA(A3) ; see if we have a phase change or something
dbne D2, @1
bne.s @phzChange ;
@outerbtm
dbra D1, @outerTop ; loop dec. on low word of blindBusTO
sub.l #$00010000, D1 ; sub 1 from high word of blindBusTO
bcc.s @outerTop ; loop if result >=0
bra.s @cleanup
; if DREQ, retry the transfer -----
@retry
move.w (sp)+, D0 ; get previous MMU mode into D0
jsr SwapMMU ; return to previous mode
movem.l (sp)+, savedRegs ; restore regs
addq.l #4, sp
rte ; haven't reached max retry count, so restart
; if phase change or timeout, cleanup and abort the transfer -----
@phzChange
@cleanup
; return to previous MMU mode and return SP to the exception stack frame
move.w (sp)+, D0 ; get previous MMU mode into D0
jsr SwapMMU ; return to previous mode
movem.l (sp)+, savedRegs ; restore regs
addq.l #4, sp ; take scratch space off stack
; get any leftover bytes out of the FIFO if we were doing a FastRead
cmp.w #scsiReadFast, transferType(A4)
bne.s @skipLeftovers
move.b rFOS(a3), D0 ; get FIFO status - how many bytes in FIFO
and.w #iFOFMsk, D0 ;
ror.l #1, D0
bra.s @btm0
@top0
move.w rDMA(a3), (A2)+ ; get word from chip and put into user's buffer
@btm0
dbra D0, @top0
tst.l D0
bpl.s @2
move.b rFFO(a3), (A2)+ ; get byte from chip and put into user's buffer
@2
; get rid of excp'n frame and create a throwaway frame for return to Transfer_PSC
@skipLeftovers
move.w xSR(sp), D0 ; save SR for new exception frame
bfextu FrameType(sp){0:4}, D1 ; get format code from stack
cmp.b #AEXFrameType, D1 ; check for 040 Access Error Exception Frame
beq.s @Drop040XFrame ; dispose of 040 AE exception frame
cmp.b #shortBEXFrameType, D1 ; short 020/030 exception frame?
bne.s @Drop46w ; no, so use larger frame
adda.w #shortBEXFrameSize, sp ; dispose of the 16-word frame
bra.s @DummyFrame ; and finish up
@Drop040XFrame ; 040 Bus Error frame-cleaning done here
add.w #aeXFrameSize, sp ; remove 040 Access Error Exception Frame
bra.s @DummyFrame ; and create dummy return frame
@Drop46w
add.w #46*2, sp ; size of exception frame
@DummyFrame
; Fake a format code 0 exception frame (4 words) to finish cleaning up
move.w zeroReg, -(sp) ; format code 0
pea FinishErr ; PC value
move.w d0, -(sp) ; sr value
rte ; 'return' from the fake exception
; If we busErr due to a slow peripheral then the c96 is still expecting to transfer
; data since it has no concept of bus error. Hopefully, the client upon seeing busTOErr
; will do the right thing and call SCSIComplete to clean up the bus.
;-----------------
FinishErr
;-----------------
; What we really need to do here is to first empty the FIFO the call Wt4DREQorIntPSC
; then do the right thing. %%%
moveq.l #scBusTOErr, d0 ; assume bus timeout
btst.b #bINT, rSTA(a3) ; poll for intrp due to premature phase change
beq.s @ErrorDone ; bra. if no SCSI intrp 'cuz we busTO
move.b rINT(a3), d5 ; got intrp so check cause also read & clear rFOS, rSTA & rINT
btst.l #bBSS, d5 ; test for bus service intrp
beq.s @ErrorDone ; bra. if not bus service
moveq.l #scPhaseErr, d0 ; yup it's a premature phase change
@ErrorDone
rts ; return status in d0 to the Transfer routine <T8> from prev <T8>
;-----------------
DoWriteBack
;-----------------
btst #bValid, D0 ; if this writeback valid?
beq.s @wbDone ; no - done
and.w #SIZE_MSK, D0 ; yes, transfer proper size
cmp.w #WB_BYTE, D0
bne.s @1
move.B D1, (A1) ; move Byte
bra.s @wbDone
@1
cmp.w #WB_WORD, D0
bne.s @2
move.W D1, (A1) ; move Word
bra.s @wbDone
@2
cmp.w #WB_LONG, D0
bne.s @wbDone
move.L D1, (A1) ; move LongWord
@wbDone
rts
ENDWITH
;==========================================================================
ENDWITH
END