mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-08-29 08:29:03 +00:00
2041 lines
77 KiB
Plaintext
2041 lines
77 KiB
Plaintext
;
|
||
; File: SCSIMgrHW96.a
|
||
;
|
||
; Contains: SCSI Manager 53C96 Hardware-Specific routines
|
||
;
|
||
; Written by: Far Too Many People
|
||
;
|
||
; Copyright: © 1990-1993 by Apple Computer, Inc. All rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM16> 8/12/93 KW conditionalizing smurf branches
|
||
; <SM15> 8/11/93 KW added some branches based on new smurf boxes
|
||
; <SM14> 5/5/93 PW Enabling FastRead and FastWrite for EVT2 PDMs.
|
||
; <SM13> 2/5/93 CSS Horror rollin. Export some entry points for the BIOS ROM SCSI
|
||
; <H5> 9/6/92 jab Exported some entry points for the BIOS ROM SCSI Mgr to use.
|
||
; mgr.
|
||
; <SM12> 1/26/93 SAM Added various NOPs after the xferCount reg gets loaded before a
|
||
; xferInfo cmd is sent for NonSerializedIO machines. Added not
|
||
; forROM conditionals around all 24-bit/swapmmu code in here just
|
||
; for grins. Crippled all fast read/write routins for PDM only to
|
||
; not be fast (ie to use the slow FIFO xfer routines till Jimmy
|
||
; fixes his shit.)
|
||
; <SM11> 12/23/92 RC Added Support for Smurf on Wombat
|
||
; <SM10> 12/11/92 SAM Removed PDM bring-up hacks.
|
||
; <SM9> 12/3/92 fau Changed the use of DAFBExists to check for the
|
||
; Spike/Eclipse/Zydeco/RiscQuadra box flag. Those registers on
|
||
; DAFB are only needed on those machines.
|
||
; <SM8> 11/3/92 SWC Changed SCSIEqu.a->SCSI.a.
|
||
; <SM7> 10/18/92 CCH Added nop's to support non-serial IO space, conditionals to use
|
||
; byte accesses to the DREQ register, and a hack to bypass
|
||
; pseudo-DMA on PDM for now.
|
||
; <SM6> 8/9/92 CCH Modified boxflag check for Spike to include boxRiscQuadra.
|
||
; <5> 5/22/92 DTY #1029009 <jab>: Modified DREQ bit testing from global (setup in
|
||
; SCSIInit96) and rearranged writebacks to conform with Moto spec.
|
||
; <4> 5/1/92 JSM Don’t use isUniversal conditional, which was commented out
|
||
; anyway. Don’t use internal GEEZ conditional, which was always
|
||
; false. Use Max020030BusErrs instead of MaxBusErr, which is
|
||
; equated differently in SCSIPriv.a depending on how CPU was
|
||
; defined. For System builds, CPU is set to 00, which gave us the
|
||
; wrong value since this file is only used on 020's and above.
|
||
; <3> 3/17/92 pvh #1021847:
|
||
; Fix the removable device bug (CD ROMs etc.) on Quadras which
|
||
; caused the “This disk is unreadable. Do you want to format?”
|
||
; dialog to randomly appear. Apparently there is a bug in the
|
||
; 53C96 chip which causes the FIFO count to get stuck on occasion.
|
||
; We now flush the FIFO buffer to make sure the count is correct.
|
||
; <2> 12/2/91 SAM Using official boxflag equates now.
|
||
; <1> 10/24/91 SAM Rolled in Regatta file.
|
||
;
|
||
; Regatta Change History:
|
||
;
|
||
; <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.
|
||
;
|
||
; Terror 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 InitSCSI96HW 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 (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_SCSI96: 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
|
||
BLANKS ON
|
||
STRING ASIS
|
||
PRINT OFF
|
||
|
||
LOAD 'StandardEqu.d' ; Load em if you got em...
|
||
INCLUDE 'HardwarePrivateEqu.a'
|
||
INCLUDE 'UniversalEqu.a'
|
||
INCLUDE 'SCSI.a'
|
||
INCLUDE 'SCSIPriv.a'
|
||
INCLUDE 'SCSIEqu96.a'
|
||
INCLUDE 'MC680x0.a'
|
||
|
||
PRINT ON
|
||
|
||
SCSIHW96 PROC EXPORT
|
||
|
||
EXPORT SlowRead_96, Transfer_96, Xfer1Byte
|
||
EXPORT Wt4DREQorInt, HandleSelInProg, WaitForIntNoTime
|
||
EXPORT ResetBus_96, WaitForSCSIIntrp
|
||
EXPORT BusErrHandler_96 ; <T8>
|
||
|
||
|
||
EXPORT InitHW_SCSI96, IntHnd_SCSI96
|
||
EXPORT SlowWrite_96, SlowComp_96 ; <T4>
|
||
EXPORT FastRead_96, FastWrite_96, FastComp_96 ; <T4>
|
||
EXPORT OneByteWrite, OneByteRead, WtForFIFOData ; <H5> <SM13> CSS
|
||
|
||
|
||
IMPORT ClearSCSIInt ; from InterruptHandlers.a <T4>
|
||
IMPORT SCSIpcTo32bit, Error, SwapMMU ; from SCSIMgr96.a <T4>
|
||
|
||
|
||
WITH scsiPB, scsiPrivPB
|
||
WITH scsiGlobalRecord, dcInstr
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
;
|
||
; InitHW_SCSI96 - 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_SCSI96
|
||
|
||
move.b #cRstSChp, rCMD(a3) ; Reset the Chip (not the bus)
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM12>
|
||
endif
|
||
move.b #cNOP, rCMD(a3) ; C96 NOP required after HW or SW reset
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
|
||
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM12>
|
||
endif
|
||
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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
|
||
; 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 @dontChk ; 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. <SM9>
|
||
|
||
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 Spike <SM15>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM15>
|
||
cmp.b #boxRiscQuadra900,ProductInfo.ProductKind(A0) ; check for a RISC Quadra900<SM15>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM15>
|
||
cmp.b #boxRiscQuadra950,ProductInfo.ProductKind(A0) ; check for a RISC Quadra950<SM15>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM15>
|
||
cmp.b #boxRiscCentris610,ProductInfo.ProductKind(A0) ; check for a RISC Centris610<SM15>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM15>
|
||
cmp.b #boxRiscCentris650,ProductInfo.ProductKind(A0) ; check for a RISC Centris650<SM15>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM15>
|
||
cmp.b #boxRiscQuadra800,ProductInfo.ProductKind(A0) ; check for a RISC Quadra800<SM15>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM15>
|
||
cmp.b #boxRiscQuadra610,ProductInfo.ProductKind(A0) ; check for a RISC Quadra610<SM16>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM16>
|
||
cmp.b #boxRiscQuadra650,ProductInfo.ProductKind(A0) ; check for a RISC Quadra650<SM16>
|
||
beq.s @DoSpikeEclipseZydeco ; Special setup for Spike/Eclipse/Zydeco <SM16>
|
||
ENDIF ; for Smurf
|
||
bra.s @dontChk ; only Spike/Eclipse have a VIA2 and DAFB
|
||
|
||
@DoSpikeEclipseZydeco ; <SM9>
|
||
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 @0 ; ELSE // Speed == 25MHz
|
||
@25MHz
|
||
move.l #tsc_cf_stg_25,(a4) ; setup DAFB SCSI config register.
|
||
; ... must move 32 bits to DAFB
|
||
@0 ; ENDIF
|
||
|
||
;******* TEMPORARY KLUDGE TO SUPPORT a 16/25Mhz Eclipse SCSI96 and *****
|
||
;******* 25Mhz Spike SCSI96 *****
|
||
;
|
||
; ASSUMPTION: If you are executing this code, you are either a Spike or Eclipse. <T6>
|
||
;
|
||
; ASSUMPTION: If you are a Spike, then you ALWAYS are a 25 MHz SCSI clock. <T6>
|
||
; If you are an Eclipse: <T6>
|
||
; If you have a 25 MHz CPUClk, you have a 15.6672 MHz SCSI clk <T6>
|
||
; If you have a 33 MHz CPUClk, you have a 24.28416 MHz SCSI clk <T6>
|
||
|
||
move.l UnivInfoPtr,A0 ; get pointer to universal table <T9>
|
||
cmp.b #boxQuadra700,ProductInfo.ProductKind(A0) ; check for a Spike <T9><2>
|
||
beq.s @ForSpike ; (note - BoxFlag is not defined yet!) <T9>
|
||
IF forSmurf THEN
|
||
cmp.b #boxRiscQuadra700,ProductInfo.ProductKind(A0) ; check for a RISC Quadra700 <SM15>
|
||
beq.s @ForSpike ; (note - BoxFlag is not defined yet!) <SM15>
|
||
cmp.b #boxRiscCentris610,ProductInfo.ProductKind(A0) ; check for a RISC Centris610 <SM15>
|
||
beq.s @ForSpike ; (note - BoxFlag is not defined yet!) <SM15>
|
||
cmp.b #boxRiscCentris650,ProductInfo.ProductKind(A0) ; check for a RISC Centris650 <SM15>
|
||
beq.s @ForSpike ; (note - BoxFlag is not defined yet!) <SM15>
|
||
cmp.b #boxRiscQuadra800,ProductInfo.ProductKind(A0) ; check for a RISC Quadra800 <SM15>
|
||
beq.s @ForSpike ; (note - BoxFlag is not defined yet!) <SM15>
|
||
cmp.b #boxRiscQuadra610,ProductInfo.ProductKind(A0) ; check for a RISC Quadra610 <SM16>
|
||
beq.s @ForSpike ; <SM16>
|
||
cmp.b #boxRiscQuadra650,ProductInfo.ProductKind(A0) ; check for a RISC Quadra650 <SM16>
|
||
beq.s @ForSpike ; <SM16>
|
||
ENDIF ; for Smurf
|
||
|
||
; Check for difference between 25 and 33MHz Eclipse machines: <T6>
|
||
|
||
btst #v2Speed,d0 ; are we running at 25 or 33 MHZ? <T6>
|
||
bne.s @33MHz ; IF Speed == 25MHz THEN <T6>
|
||
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>
|
||
@33MHz ; ELSE // Speed == 33MHz <T6>
|
||
* fall thru to @ForSpike *
|
||
; move.b #ccf20to25MHz, rCKF(a3) ; load clock conversion factor (CCF) value <T6>
|
||
; move.b #SelTO25Mhz, rSTO(a3) ; load select/reselect timeout value <T6>
|
||
; bra.s @1 ; ENDIF // Speed
|
||
|
||
@ForSpike
|
||
* fall thru to @dontChk. *clkCnvVal* == *ccf20to25MHz*; *SelTO25Mhz* == *slcTimeout* <T6>
|
||
; move.b #ccf20to25MHz, rCKF(a3) ; load clock conversion factor (CCF) value
|
||
; move.b #SelTO25Mhz, rSTO(a3) ; load select/reselect timeout value
|
||
; bra.s @1
|
||
|
||
;********** TEMPORARY - DELETE WHEN SCSI CLOCK IS FINALIZED
|
||
;********** /// END of KLUDGE ///
|
||
|
||
;**** The 2 lines below are the correct code and UN-comment them.
|
||
; Delete the kludge section above when scsi clock is finalized
|
||
@dontChk
|
||
move.b #ccf20to25MHz, rCKF(a3) ; load clock conversion factor (CCF) value
|
||
move.b #SelTO25Mhz, rSTO(a3) ; load select/reselect timeout value
|
||
@1
|
||
|
||
IF forPDMDebug THEN ; SAM (someone shouyld fix that shit above!) <SM12>
|
||
move.b #ccf15to20MHz, rCKF(a3) ; load clock conversion factor (CCF) value
|
||
move.b #SelTO16Mhz, rSTO(a3) ; load select/reselect timeout value
|
||
nop
|
||
ENDIF
|
||
|
||
move.b #initOp, rSYO(a3) ; select syn or async operation; if sync then
|
||
; sync offset value must be nonzero
|
||
; Set synch xfer period and offset if using
|
||
; synch data xfer
|
||
@4
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
move.b rINT(a3), d0 ; read & clear rFOS, rSTA & rINT into throwaway <T6>
|
||
rts
|
||
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
;
|
||
; IntHnd_SCSI96 - This is the SCSI96 interrupt handler
|
||
; Called by: Macintosh Interrupt Dispatcher
|
||
;
|
||
; Regrs saved: a0-a5/d0-d7
|
||
;
|
||
|
||
IntHnd_SCSI96
|
||
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_96 - <T7> thru next <T7>
|
||
;
|
||
; Called by: dataCommon_96
|
||
; (NewSCSIWBlind_96, NewSCSIWrite_96, NewSCSIRBlind_96, NewSCSIRead_96)
|
||
;
|
||
; 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_96:
|
||
link a6, #linkSize ; allocate local storage
|
||
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
|
||
IF NOT forPDMDebug THEN
|
||
adda.l #nonSerlzdDisp,a1 ; point to non-serialized chip image
|
||
ENDIF
|
||
|
||
bsr HandleSelInProg ; 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>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
|
||
; 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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
jsr.w WaitForIntNoTime ; 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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM12>
|
||
endif
|
||
jsr.w WaitForIntNoTime ; 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 ; call Error proc - for debug
|
||
clr.l d1 ; no bytes transferred
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
rts ; <T4>
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
; Xfer1Byte - 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
|
||
move.b #cIOXfer, rCMD(a3) ; load IO transfer cmd & begin xfers
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
jsr.w WaitForIntNoTime ; 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:
|
||
;
|
||
; 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
|
||
;
|
||
|
||
SlowRead_96
|
||
bsr HandleSelInProg ; 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.s phaseErr1 ; bra. on phase err
|
||
|
||
clr.l d6 ;
|
||
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 ; 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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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
|
||
IF forPDMDebug THEN ; <SM7>
|
||
move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ELSE
|
||
move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ENDIF
|
||
move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab
|
||
btst.l d0, d5 ; DREQ ? <5> jab
|
||
beq.s @1 ; loop until asserted
|
||
btst #4, rFOS(a3) ; see if FIFO is full
|
||
beq.s @1 ; loop until asserted
|
||
@10
|
||
|
||
nop ; squoosh pipeline <T8>
|
||
move.w rDMA(a1), (a2)+ ; read 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)+ ; <T7> from last <T7>
|
||
IF nonSerializedIO THEN
|
||
nop ; squoosh pipeline <T8>
|
||
ENDIF
|
||
|
||
; 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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
@3
|
||
btst.b #bINT, rSTA(a3) ; check for c96 INTRP
|
||
beq.s @3 ; loop until we get an intrp
|
||
move.b rFFO(a3), (a2)+ ; xfer byte from FIFO into input buffer
|
||
|
||
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
|
||
@goodSRead ; d1 = # of bytes transferred
|
||
moveq.l #noErr, d0 ; successful read op
|
||
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), (a2)+
|
||
@btmLeftovers
|
||
dbra d0,@topLeftovers
|
||
@removeDREQ
|
||
IF forPDMDebug THEN ; <SM7>
|
||
move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ELSE
|
||
move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ENDIF
|
||
move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab
|
||
btst.l d0, d5 ; DREQ ? <5> jab
|
||
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 ; 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
|
||
; <T8> from prev <T8>
|
||
; 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 @badSRead ;
|
||
|
||
@xferErr ; anything else is a comm. err
|
||
moveq.l #scCommErr, d0 ; transfer error
|
||
@badSRead
|
||
add.l d2, d6 ; add un-xferred remainder
|
||
sub.l d6, d1 ; number of bytes transferred
|
||
|
||
move.l #scsiRead, d6 ; load proc ID
|
||
jsr Error ; call Error proc - for debug
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
rts ; <T5>
|
||
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
; 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_96
|
||
bsr HandleSelInProg ; handle unfinished select command
|
||
bne.w @phaseErr ; if it is stuck, we are not in data phase
|
||
@doWrite
|
||
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
|
||
@next64KB
|
||
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
||
and.b rSTA(a3), d3 ; are we still in data-out phase?
|
||
; and.b d5, d3 ; are we still in data-out phase?
|
||
;; cmpi.b #iDataOut, d3 ; data-out phase bits = 000
|
||
bne.w @phaseErr ; bra. if phase err
|
||
|
||
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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM12>
|
||
endif
|
||
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers
|
||
nop ; squoosh pipeline <T8>
|
||
; DREQ* should be active at this time
|
||
move.l d2, d4 ; d4 <- d2
|
||
lsr.l #4, d4 ; divide xfer count by 16
|
||
ror.l #1, d2 ; xfer byte count to word & remember odd byte
|
||
and.w #$7, d2 ; d2 = remainder word count after 16-byte moves
|
||
neg.w d2 ; negate to form a backward jump offset
|
||
jmp @emptyWait(d2.w*4) ; bra. into the loop <T4>
|
||
@write16 ;
|
||
nop ; squoosh pipeline <T8>
|
||
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) ; <T7> from last <T7>
|
||
@emptyWait
|
||
IF nonSerializedIO THEN
|
||
nop ; squoosh pipeline <T8>
|
||
ENDIF
|
||
btst.b #bINT, rSTA(a3) ; ...poll for unexpected intrp while waiting
|
||
bne.s @prematureEnd ; ... maybe disconnected, phase changed, etc.
|
||
|
||
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
||
and.b rSTA(a3), d3 ; are we still in data-out phase?
|
||
;; ;cmpi.b #iDataOut, d3 ; data-out phase bits = 000
|
||
bne.s @prematureEnd ; bra. if phase err
|
||
|
||
moveq.l #iFOFMsk, d0 ; use mask to get FIFO flag field <T8>
|
||
and.b rFOS(a3), d0 ; get # of bytes in FIFO
|
||
bne.s @emptyWait ; bra. if FIFO is empty else... <T4> thru next <T4>
|
||
@1
|
||
dbra d4, @write16 ; d4 = # of 16-byte tranfers
|
||
|
||
btst.l #31, d2 ; check if we have a residual byte
|
||
beq.s @noResidual ;
|
||
@residual
|
||
move.b (a2)+, rDMA(a3) ; xfer residual byte <T8>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
@noResidual
|
||
bsr.w WaitForIntNoTime ; 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 <T4>
|
||
dbra d6, @next64KB ;
|
||
@goodSWrite ; d1 = # of bytes transferred
|
||
moveq.l #noErr, d0 ; successful write op
|
||
rts ;
|
||
|
||
@prematureEnd ; <T4> thru next <T4>
|
||
; 3 reasons to get an intrp 1) when TC=0 (bus service), xfer done 2) premature
|
||
; phase changes (bus service) 3) premature disconnect (disconnect)
|
||
bsr.w WaitForIntNoTime ; Clear pending intrp & get err status
|
||
; on exit d5 = rFOS|rINT|0|rSTA
|
||
btst.l #bTRC, d5 ; Maybe we're done xferring data ie. TC=1
|
||
bne.s @2 ; ...so proceed with next 64Kb block
|
||
|
||
moveq.l #iPhaseMsk, d3 ; load mask bits for phase value
|
||
and.b d5, d3 ; are we still in data-out phase? (d5 from WaitFor call)
|
||
cmpi.b #iDataOut, d3 ; data-out phase bits = 000
|
||
beq.s @xferErr ; bra. if not phase err
|
||
@phaseErr
|
||
moveq.l #scPhaseErr, d0 ; return a phase error
|
||
move.l #0, d1 ; no bytes transferred
|
||
move.l #0, G_FakeStat(a4) ; Return a fake status
|
||
bra.s @bytesXferd
|
||
|
||
@xferErr
|
||
moveq.l #scCommErr, d0 ; comm error
|
||
@bytesXferd
|
||
lsl.l #4, d4 ; multiply by 16
|
||
swap d6 ; calculate bytes left to transfer
|
||
move.w d4, d6 ; get low order word
|
||
moveq.l #iFOFMsk, d2 ; <T8>
|
||
and.b rFOS(a3), d2 ; add # of un-xferred data in FIFO
|
||
add.l d2, d6 ;
|
||
sub.l d6, d1 ; d1 = bytes xferred
|
||
@badSWrite
|
||
move.l #0, G_FakeStat(a4) ; Return a fake status
|
||
move.l #scsiWrite, d6 ; load proc ID
|
||
jsr Error ; call Error proc - for debug
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T4>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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_96
|
||
IF forPDMDebug THEN ; <SM12> Jimmy, Jimmy, Jimmy....
|
||
cmp.b #$44,$CB3 ; PDM evt1?
|
||
bne.s @fast ; -> Nope, its ok to do fast
|
||
bra SlowWrite_96
|
||
@fast
|
||
ENDIF
|
||
|
||
bsr HandleSelInProg ; 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>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM12>
|
||
endif
|
||
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers
|
||
; DREQ* should be active at this time
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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 nonSerializedIO 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>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
@noResidual
|
||
bsr.w WaitForIntNoTime ; 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>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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 ; call Error proc - for debug
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T4>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
rts ;
|
||
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
; FastRead - 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
|
||
|
||
FastRead_96
|
||
IF forPDMDebug THEN ; <SM12> Jimmy, Jimmy, Jimmy....
|
||
cmp.b #$44,$CB3 ; PDM evt1?
|
||
bne.s @fast ; -> Nope, its ok to do fast
|
||
bra SlowRead_96
|
||
@fast
|
||
ENDIF
|
||
bsr HandleSelInProg ; 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>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
; 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 nonSerializedIO THEN
|
||
nop ; squoosh pipeline <T8>
|
||
ENDIF
|
||
; INT & TC bits should be TRUE at this point
|
||
bsr.w WaitForIntNoTime ; 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 ; call Error proc - for debug
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <T4>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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_96
|
||
; disable all intrps
|
||
move.b #cRstSBus, rCMD(a3) ; load reset scsi bus cmd <T3>
|
||
; re-enable all intrps
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
rts
|
||
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
;
|
||
; WaitForIntNoTime - 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
|
||
@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>
|
||
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
;
|
||
; HandleSelInProg
|
||
;
|
||
; 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)
|
||
;
|
||
HandleSelInProg
|
||
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 Wt4DREQorInt
|
||
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
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO <3>
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
moveq.l #0, d0
|
||
bra.s @gotInt
|
||
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
;
|
||
; Wt4DREQorInt - 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
|
||
;
|
||
;-----------------
|
||
|
||
Wt4DREQorInt
|
||
jsr SCSIpcTo32bit ; 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 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
|
||
IF forPDMDebug THEN ; <SM7>
|
||
move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ELSE
|
||
move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ENDIF
|
||
|
||
; out of 32-bit mode (return to previous mode - already in D0)
|
||
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
|
||
|
||
; DREQ?
|
||
move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab
|
||
btst.l d0, d5 ; DREQ ? <5> jab
|
||
beq.s @noTimeout ; no: try again
|
||
|
||
@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
|
||
;
|
||
; 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
|
||
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
|
||
@exit
|
||
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 @exit ;
|
||
|
||
|
||
|
||
|
||
;--------------------------------------------------------------------------
|
||
; 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_96
|
||
IF forPDMDebug THEN ; <SM12> Jimmy, Jimmy, Jimmy....
|
||
bra SlowComp_96
|
||
ENDIF
|
||
bsr HandleSelInProg ; 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 <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_96 ; <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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
|
||
ror.l #1, d2 ; xfer byte count to word & remember odd byte
|
||
subq.w #1, d2 ; adjust for DBRA
|
||
@RdAndCmp
|
||
move.w rDMA(a3), d0 ; <T8>
|
||
cmp.w (a2)+, d0 ; compare a word at a time
|
||
beq.s @Ok
|
||
moveq.l #scCompareErr, d3 ; record a compare error
|
||
@Ok
|
||
dbra d2, @RdAndCmp ; loop until done
|
||
; INT & TC bits should be TRUE at this point
|
||
bsr.w WaitForIntNoTime ; 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
|
||
move.b rFFO(a3), d0 ; read byte data from FIFO
|
||
cmp.b (a2)+, d0 ; xfer byte from FIFO into input buffer
|
||
beq.s @2
|
||
moveq.l #scCompareErr, d3 ; record a compare error
|
||
@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 ;
|
||
|
||
@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 ; call Error proc - for debug
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
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_96
|
||
bsr HandleSelInProg ; 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 a DREQ in nuBus
|
||
; address space. We don't need to do this if we're xferring <16 bytes.
|
||
|
||
jsr SCSIpcTo32bit ; 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 #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
|
||
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & start loading FIFO
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
@1 ; currently loaded transfer count is used/reused
|
||
btst.b #bINT, rSTA(a3) ; poll for unexpected intrp while waiting
|
||
bne.s @prematureEnd ; ... maybe disconnected, phase changed, etc.
|
||
btst.b #bTRC, rSTA(a3) ; check if we've rcvd all the data
|
||
beq.s @1 ; loop until FIFO is full
|
||
|
||
; 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.
|
||
|
||
IF forPDMDebug THEN ; <SM7>
|
||
move.b (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ELSE
|
||
move.l (a0), d5 ; read DAFB regr (a0=DAFB register addr)
|
||
ENDIF
|
||
move.b G_bitDREQ(a4),d0 ; load DREQ bit position <5> jab
|
||
btst.l d0, d5 ; DREQ ? <5> jab
|
||
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
|
||
beq.s @Ok1
|
||
moveq.l #scCompareErr, d3 ; record a compare error
|
||
@Ok1 dbra d5, @cmpFFO ; continue with compare operation
|
||
@2 ; Intrp should occur after ALL data have been
|
||
; read out of the FIFO
|
||
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
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
@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 ;
|
||
|
||
@prematureEnd
|
||
bsr.w WaitForIntNoTime ; Clear pending intrp & get err status
|
||
; on exit d5 = rFOS|rINT|0|rSTA
|
||
@premature2
|
||
move.b (sp)+, d0 ; switch to previous address mode
|
||
jsr SwapMMU ; do it, call _SwapMMUMode jump vector
|
||
; calc how many bytes were 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 ; call Error proc - for debug
|
||
move.b #cFlshFFO, rCMD(a3) ; Flush FIFO
|
||
if nonSerializedIO Then
|
||
nop ; Force write to complete. <SM7>
|
||
endif
|
||
rts ; <T5>
|
||
|
||
|
||
|
||
|
||
;___________________________________________________________________________ <T8> to next <T8>
|
||
;
|
||
; BusErrHandler_96
|
||
; 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_96 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-D3/A0-A1 ; save these registers because we need to use them <jab> added D3
|
||
savedRSize EQU 6*4 ; # bytes on stack for saved registers <jab> added D3
|
||
|
||
BusErrHandler_96
|
||
|
||
; 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
|
||
|
||
; 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 ; 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
|
||
move.b G_bitDREQ(a4),d3 ; load DREQ bit position <5> jab
|
||
btst.l d3, d0 ; DREQ ? <5> jab
|
||
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 d3, d0 ; DREQ ? <5> jab
|
||
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
|
||
|
||
; Clean up the writebacks on the stack frame <5> thru to next <5> jab
|
||
|
||
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
|
||
|
||
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 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 <5> jab
|
||
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_96
|
||
|
||
@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 Wt4DREQorINT
|
||
; 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
|