mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-02-02 03:32:31 +00:00
0ba83392d4
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.
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
|