mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-12-12 04:29:09 +00:00
1149 lines
40 KiB
Plaintext
1149 lines
40 KiB
Plaintext
;____________________________________________________________________________________
|
|
;
|
|
; File: HALc96DMA.a
|
|
;
|
|
; Contains: Stuff for 53c96 machines with some kind of DMA (Cyclone, PDM etc.)
|
|
;
|
|
; Written by: Paul Wolf
|
|
;
|
|
; Copyright: © 1990-1993 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; NOTE! This file is INCLUDED by HALc96PSC.a and HALc96AMIC.a, it is not assembled
|
|
; separately. Each of these includers, set up the build flags according to
|
|
; the requirements of that hardware.
|
|
;
|
|
; The flags/equates used in this process are:
|
|
; Symbol ————— AMIC value ————— PSC value —————
|
|
; DMA_MinMemoryXfer 8 16
|
|
; DMA_NeedsCount FALSE TRUE
|
|
; DMA_WriteNeedsReset FALSE TRUE
|
|
; DMA_Title AMIC PSC
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM17> 11/22/93 pdw Rolling in from <MCxx>.
|
|
; <MC8> 10/29/93 pdw Removed _debugger statements.
|
|
; <MC7> 10/29/93 pdw Fixed the buserror caused by DMAi when VM is on by using the
|
|
; logical address instead of the physical when doing alignment!
|
|
; Also enhanced the alignment code to use dmaAlignMask so it's
|
|
; accurate both for PSC and AMIC.
|
|
; <SM16> 10/29/93 pdw Got rid of _Debugger statements that screwed some things.
|
|
; <SM15> 10/29/93 DCB <MC> roll-in.
|
|
; <MC6> 10/28/93 pdw Fixed some DMA in and out residual length bugs.
|
|
; <SM14> 10/15/93 pdw Getting rid of bogus forPDMProto.
|
|
; <SM13> 10/14/93 pdw <MC> roll-in.
|
|
; <MC4> 10/12/93 pdw Changed and.b to and.l in DMAo so that the following bne.s does
|
|
; what it's meant to do.
|
|
; <MC3> 10/12/93 pdw Added support for Synchronous data transfers, rewrote State
|
|
; Machine, message handling etc.
|
|
; <MC2> 10/6/93 pdw Added forPDMProto stuff around checks for doRealDMAxxx.
|
|
; <SM12> 9/12/93 pdw Changed the size of the double-buffering buffer.
|
|
; <SM11> 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug
|
|
; stuff.
|
|
; <SM10> 8/13/93 pdw RecordCmd and eieio stuff.
|
|
; <SM9> 7/19/93 pdw Got rid of a beq.s to the next instruction to get rid of build
|
|
; warning.
|
|
; <SM8> 7/17/93 pdw Lots of little things. Some major things.
|
|
; <SM7> 6/29/93 pdw Massive checkins: Change asynchronicity mechanism to CallMachine
|
|
; stack switching mechanism. Adding support for Cold Fusion.
|
|
; Rearranging HW/SW Init code. Some code optimizations.
|
|
; <SM6> 5/26/93 PW Moving the restore of the CF3 register till after the loop in
|
|
; DataIn_DMA and DataOut_DMA.
|
|
; <SM5> 5/25/93 DCB Rollin from Ludwig. (The next item below)
|
|
; <LW7> 5/21/93 PW Changing some DebugStrs to IfDebugStrs+Syserr.
|
|
; <LW6> 5/20/93 DCB Changing _debuggers to DebugStrs so we can turn them off at
|
|
; compile time.
|
|
; <SM4> 5/5/93 PW Converted names to meanies-friendly names. Updated with latest
|
|
; from Ludwig stuff.
|
|
; <SM3> 3/29/93 PW Slight rearrangement of forPDMProto so that I could put in the
|
|
; btst for useRealDMARead and useRealDMAWrite flags. Created
|
|
; pseudo-real DMA write and read routines to use if these bits
|
|
; aren't set.
|
|
; <LW4> 3/31/93 DCB Changing the bhi's I put in last night to bhs's which is what
|
|
; they should have been.
|
|
; <LW3> 3/30/93 DCB Changing a couple of bge's to bhi's to fix a hang with large RAM
|
|
; disks. Essentially the GetPhysical translation got screwed up
|
|
; because of a very large address that was interpreted as
|
|
; negative.
|
|
; <LW2> 3/26/93 PW Fixed serious misalignment/disconnection bug by using the
|
|
; StopReadDMA result in D0 instead of rXCx when not on a PDM.
|
|
; <1+> 3/21/93 PW Removing bra to SlowWrite - using HALc96Init to configure
|
|
; instead.
|
|
; <1> 3/20/93 PW first checked in
|
|
;
|
|
; HALc96PSC.a Change History (before split into …DMA.a, …AMIC.a and …PSC.a)
|
|
; <SM19> 3/4/93 PW Made GPHYSICAL optional through -d.
|
|
; <LW6> 3/1/93 DCB Added conditional compile for GetPhysical call. This aids
|
|
; performance testing.
|
|
; <LW5> 2/17/93 PW Removed some old Terror change tags.
|
|
; <SM18> 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM
|
|
; (will update Ludwig with these as needed myself).
|
|
; <LW4> 1/27/93 DCB Added workaround to a bug in the HWPriv.a GetPhysical. Seems
|
|
; that in cases where the logical range was not contiguous the
|
|
; logical address and count in the table were not updated
|
|
; correctly. The workaround reconstructs these fields manually so
|
|
; we don't get stuck in a loop.
|
|
; <LW3> 1/27/93 PW Got rid of some bad comments.
|
|
; <LW2> 1/6/93 DCB Check kbUseDblBuffer bit in the SIMprivFlags if an address in
|
|
; the Parameter Block is in the ROM or above. This fixes the SCSI
|
|
; into NuBus bug. Radar Bug # 1059322. This prevents the PSC from
|
|
; doing DMA to addresses it can't handle by DMAing into a known
|
|
; locked down buffer and then blockmoving out to the NuBus
|
|
; address.
|
|
; <SM17> 12/5/92 PW Changed field names. Added phase check at beginning of
|
|
; DataInPSC_DMA. Cleaned up alignment setup.
|
|
; <SM16> 11/20/92 DCB Fixed minor problem where DataOutPSC might inadvertantly return
|
|
; an error (nobody was paying attention to it but still...)
|
|
; <SM15> 11/12/92 PW Added missing # sign causing failed Writes if BetterBusError
|
|
; installed.
|
|
; <SM14> 10/30/92 DCB Added support for direct DMA (!!!)
|
|
; <SM13> 10/14/92 PW Put in the real fix for the premature phase change on DMA write
|
|
; bug - flushed FIFO and subtracted unxferred count from xferred
|
|
; count.
|
|
; <SM12> 10/8/92 PW Changed BFR_SIZE to 512 until I get a real fix for premature
|
|
; phase change on write bug.
|
|
; <SM11> 10/8/92 PW Added write/read/compare CNT and ADDR register writes to help in
|
|
; discovering possible PSC bug. Note: PSC_WRITE_CHECK flag must
|
|
; be set to 1 to enable the DebugStr when miscompare occurs.
|
|
; <SM10> 10/8/92 PW Lots of trivial name changes. Added GrossError checks. (cb)
|
|
; Fixed bug with .w vs .l direction parameter to StartDMA.
|
|
; <SM9> 9/30/92 fau After talking to PW, I added a TestFor YMCADecoder to enable DMA
|
|
; Writes on EVT4's, since they all have the Curio B0.
|
|
; <SM8> 8/31/92 PW Changed register and command definitions to reflect changes to
|
|
; SCSIEqu53c96.
|
|
; <SM7> 8/31/92 PW Fixed bug that trashed Jeff Boone's drive. It was a bad
|
|
; remainder count being setup after OneByteWrite in
|
|
; DataOut_PSC1x1.
|
|
; <SM6> 8/30/92 PW Added DMA Write stuff. Currently disabled unless 'sw c0c^+200
|
|
; 0000' is issued.
|
|
; <SM5> 8/1/92 PW Fixed write bug for 1,511 TIBs. Greatly increased speed of
|
|
; alignment process. Particularly critical in 1,511 TIBs.
|
|
; <SM4> 7/29/92 PW Changed test for 1 byte transfer so that it uses OneByteRead
|
|
; instead of attempting to use DMA.
|
|
; <SM3> 7/28/92 PW Adding slight StopDMA changes.
|
|
; <SM2> 7/27/92 PW Got DMA working.
|
|
; <SM1> 7/27/92 PW Virtually initial check-in.
|
|
;
|
|
;____________________________________________________________________________________
|
|
|
|
|
|
MACHINE MC68020 ; '020-level
|
|
BLANKS ON ; assembler accepts spaces & tabs in operand field
|
|
PRINT OFF ; do not send subsequent lines to the listing file
|
|
; don't print includes
|
|
|
|
BFR_SIZE EQU $1000 ; Size of Buffer for Double Buffering
|
|
MIN_PSC_DMA_SIZE EQU $200 ; Double Buffer at or below this value
|
|
MIN_AMIC_DMA_SIZE EQU $20 ; Double Buffer at or below this value
|
|
; Check HALc96PSC.c also!
|
|
WEIRDSHIT equ 0
|
|
wholeErrors equ 1
|
|
INCLUDE 'SysErr.a'
|
|
INCLUDE 'SysEqu.a'
|
|
INCLUDE 'HardwarePrivateEqu.a'
|
|
INCLUDE 'TrapsPrivate.a'
|
|
INCLUDE 'Debug.a' ; for NAME macro
|
|
|
|
INCLUDE 'SCSI.a'
|
|
INCLUDE 'SCSIEqu53c96.a'
|
|
INCLUDE 'ACAM.a'
|
|
INCLUDE 'SIMCoreEqu.a'
|
|
|
|
INCLUDE 'HALc96equ.a'
|
|
|
|
PRINT ON ; do send subsequent lines to the listing files
|
|
CASE OBJECT
|
|
|
|
|
|
IMPORT RecordEvent
|
|
IMPORT Wt4SCSIInt
|
|
IMPORT OneByteRead, OneByteWrite
|
|
IMPORT Ck4DREQ, Ck4SCSIInt
|
|
|
|
; IMPORT MungeScreen
|
|
IMPORT AsmInit53c9xHW
|
|
IMPORT DoSelect
|
|
|
|
IMPORT FastRead96
|
|
|
|
;--------------------------------------------------------------------------
|
|
; DataIn_DMA - implements DMA Read
|
|
;
|
|
; Called by: Transfer
|
|
;
|
|
; All primitive data transfer routines assume:
|
|
;
|
|
; Inputs --->
|
|
; -> D2.L number of bytes to transfer
|
|
; -> D1.L copy of d2
|
|
; -> A1 SCSI chip read base address - NON-SERIALIZED
|
|
; -> A2 ptr to data buffer - saved
|
|
; -> A3 SCSI chip read base address - SERIALIZED
|
|
; -> A5 ptr to SCSI Mgr globals
|
|
;
|
|
; Outputs <---
|
|
; <- D0.W error (if any)
|
|
; <- D1.L bytes transferred
|
|
; <- D5.L xxxx|xxxx|xxxx|rSTA
|
|
; <- D3 scratch - saved
|
|
; <- D4
|
|
; <- D6 scratch - saved
|
|
;
|
|
;
|
|
|
|
DataIn_DMA1x1 PROC EXPORT
|
|
|
|
WITH HALc96GlobalRecord
|
|
|
|
IF 1 AND RECORD_ON THEN
|
|
pea '1x1i' ; EVENT =
|
|
move.l D2, -(sp) ; number of bytes
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
move.l d2, d3 ;
|
|
swap d3 ; d3.w:d2.w = total#bytes to xfer
|
|
bra.s @LpReadBtm
|
|
@LpReadTop
|
|
move.b #cIOXfer, rCMD(a3) ; load non-DMA transfer cmd & begin 1 byte xfer
|
|
eieio
|
|
;
|
|
; WtForInt
|
|
;
|
|
@noTimeoutWait
|
|
clr.l d5 ;
|
|
move.b rSTA(a3), d5 ; read Status regr
|
|
bpl.s @noTimeoutWait ; ...loop until intrp req is detected
|
|
|
|
move.b D5, D0
|
|
and.b #iPhaseMsk, D0
|
|
move.b D0, currentPhase(A5)
|
|
|
|
swap d5 ;
|
|
move.b rFIFOflags(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
|
|
; get Disconnect & Bus Service bits
|
|
andi.b #(1<<bDisconnected)+(1<<bBusService), d0
|
|
cmpi.b #1<<bBusService, d0 ; expecting: not disconnected
|
|
bne.s @disconnected ; bra. if ended up disconnected
|
|
|
|
; WtForInt routine that fails!!!
|
|
;@1
|
|
; btst.b #bINT, rSTA(a3) ; INT?
|
|
; beq.s @1
|
|
; btst.b #bDisconnected, rINT(a3)
|
|
; bne.s @disconnected ; bra. if ended up disconnected
|
|
|
|
move.b rFIFO(a3), (a2)+ ; get the byte
|
|
@LpReadBtm
|
|
moveq.l #iPhaseMsk, d0 ; load mask for phase bits
|
|
and.b rSTA(a3), d0 ; are we in data-in phase?
|
|
cmpi.b #iDataIn, d0 ; data-in phase bits = 001
|
|
bne.s @phaseErr ; bra. on phase err
|
|
|
|
dbra d2, @LpReadTop ; d2 = low word of count
|
|
dbra d3, @LpReadTop ; d3 = high word of count
|
|
|
|
moveq.l #0, d1
|
|
@disconnected
|
|
@good ; d1 = # of bytes transferred
|
|
rts ;
|
|
|
|
@phaseErr
|
|
swap d3 ; calculate bytes left to transfer
|
|
move.w d2, d3 ; merge words
|
|
move.l d3, d1
|
|
rts ;
|
|
|
|
NAME 'DataIn_DMA1x1'
|
|
|
|
ENDWITH
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
|
|
DataIn_DMA PROC EXPORT
|
|
;
|
|
; Register Usage:
|
|
;
|
|
; ———————— On Entry:———————————————————————————————————————————————
|
|
D2_totalLeft EQU D2
|
|
A2_userBuffer EQU A2
|
|
;
|
|
; ———————— On Exit:———————————————————————————————————————————————
|
|
D1_xferSize EQU D1 ; .l =
|
|
;
|
|
;
|
|
; ———————— Internal:———————————————————————————————————————————————
|
|
D3_alignOffset EQU D3 ; .l = offset required for alignment of buffers
|
|
A1_physicalBfr EQU A1
|
|
|
|
|
|
WITH HALc96GlobalRecord
|
|
WITH SIMprivFlagsRecord
|
|
WITH SIM_IO, SCSIPhase
|
|
|
|
IF 1 AND RECORD_ON THEN
|
|
pea 'DMAi' ; EVENT =
|
|
move.l D2_totalLeft, -(sp) ; number of bytes
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
;
|
|
; Make sure that we're in DataIn phase before transferring
|
|
;
|
|
cmpi.b #kDataInPhase, currentPhase(A5)
|
|
bne @phaseErrAtStart ; bra. on phase err
|
|
|
|
;
|
|
; If we are transferring either 1 or 0 bytes, either do a OneByteRead or noTransfer
|
|
;
|
|
cmp.l #1, D2_totalLeft
|
|
bgt.s @doLots
|
|
bne @noTransfer
|
|
bsr OneByteRead
|
|
moveq.l #0, D2_totalLeft
|
|
bra @good
|
|
@doLots
|
|
;
|
|
; 1st TIME THRU ———— Alignment ————
|
|
;
|
|
; Adjust our DMA buffer addresses on 1st Time Thru to line up with the
|
|
; user's buffer start. That way BlockMove will be able to use MOVE16 for
|
|
; the body of the transfer.
|
|
;
|
|
move.l A2_userBuffer, D3 ; get user's buffer address
|
|
move.w dmaAlignMask+2(A5), D0 ; word-length alignment mask (00…11)
|
|
and.w D0, D3 ; get distance above alignment
|
|
beq.s @doneAligning ; if zero, skip alignment
|
|
eor.w D0, D3 ; number of bytes till alignment (1->E)
|
|
; doesn't require -1 for dbra
|
|
|
|
@alignLoop
|
|
RecCmd $10, 'M',$01
|
|
move.b #cIOXfer, rCMD(a3) ; load non-DMA transfer cmd & begin 1 byte xfer
|
|
eieio
|
|
;
|
|
; WtForInt
|
|
;
|
|
@noTimeoutWait
|
|
clr.l d5 ;
|
|
move.b rSTA(a3), d5 ; = x | x | x | rSTA
|
|
bpl.s @noTimeoutWait ; ...loop until intrp req is detected
|
|
|
|
move.b D5, D0
|
|
and.b #iPhaseMsk, D0
|
|
move.b D0, currentPhase(A5)
|
|
|
|
swap d5 ; = x | rSTA | x | x
|
|
move.b rFIFOflags(a3), d5 ; = x | rSTA | x | rFOS
|
|
lsl.w #8, d5 ; = x | rSTA | rFOS | x
|
|
move.b rINT(a3), d5 ; = x | rSTA | rFOS | rINT
|
|
move.l d5, d0 ; for checking for disconnect
|
|
|
|
move.b rFIFO(a3), (a2)+ ; get the byte
|
|
subq.l #1, D2_totalLeft
|
|
beq @good ; if xfer complete - done
|
|
|
|
; get Disconnect & Bus Service bits
|
|
andi.b #(1<<bDisconnected)+(1<<bBusService), d0
|
|
cmpi.b #1<<bBusService, d0 ; expecting: not disconnected
|
|
bne.w @disconnected ; bra. if ended up disconnected
|
|
;
|
|
; Make sure that we're in DataIn phase between each byte
|
|
;
|
|
cmpi.b #kDataInPhase, currentPhase(A5)
|
|
bne @good ; bra. on phase err
|
|
|
|
@alignLpBtm
|
|
dbra d3, @alignLoop ; check to see if we are done aligning
|
|
|
|
|
|
; ———— No alignment or done aligning ————
|
|
|
|
@doneAligning
|
|
; load init config. value. Either leaving it at regular or bumping to Threshold-8 mode
|
|
move.b rCF3DMAVal(A5), rCF3(a3)
|
|
|
|
; remember which xfer type we are doing (ParameterBlock)
|
|
; setup buffers the old way if we aren't doing full DMA
|
|
; else setup buffers the new way
|
|
|
|
bclr #noBlockMove,dmaFlags(a5) ; assume that we aren't going to DMA directly to the user's buffer
|
|
|
|
cmp.l minDMAsize(a5),D1_xferSize ; !!! is this a small buffer? (Size should correspond with HALc96PSC.c!)
|
|
ble.s @decidedXferType ; yep, use DMA/Blockmove for small buffers
|
|
|
|
cmp.b #SCSIOldCall,scsiFunctionCode(a0) ; Check to see if it is an old call
|
|
beq.s @decidedXferType ; use the old DMA/Blockmove method for TIBs
|
|
|
|
move.l scsiFlags(a0),d0 ; get the flags field
|
|
andi.l #scsiDataPhys,d0 ; did the client pass in a physical address?
|
|
bne.s @directDMA ; yep, do straight DMA
|
|
|
|
btst #kbUseDblBuffer,SIMprivFlags(a0) ; Are we doing direct DMA for this guy?
|
|
bne.s @decidedXferType ; nope, use DMA/Blockmove for small buffers
|
|
@directDMA
|
|
bset #noBlockMove,dmaFlags(a5) ; remember that we are going directly to the user's buffer
|
|
@decidedXferType
|
|
|
|
;
|
|
; 2nd TIME THRU ---- (and beyond that)
|
|
;
|
|
; If it's not the 1st time thru, we don't have to do any front alignment stuff since
|
|
; it's already aligned.
|
|
;
|
|
@loopTop
|
|
move.l A2_userBuffer,logBuffer(a5) ; save the logical address for later
|
|
IF forPDMProto THEN
|
|
move.l A2_userBuffer, dbug0(A5)
|
|
ENDIF
|
|
btst #noBlockMove,dmaFlags(a5) ; directly to the user's buffer?
|
|
bne.s @newWay ; yes -> get physical address
|
|
IF forPDMProto THEN
|
|
move.l logicalCopyBuffer(A5), dbug0(A5) ; buffer is our physical copy buffer
|
|
ENDIF
|
|
move.l #BFR_SIZE, D1_xferSize ; no, assume we'll xfer a whole buffer
|
|
bra.w @setupCount ; -> need to figure only how many
|
|
@newWay
|
|
move.l scsiFlags(a0),d0 ; get the flags field
|
|
andi.l #scsiDataPhys,d0 ; did the client pass in a physical address?
|
|
beq.s @checkAddress ; nope, get the physical address
|
|
move.l #$10000,D1_xferSize ; yep, get them dogies movin!
|
|
bra.s @setupCount
|
|
@doGetPhys
|
|
move.l A2_userBuffer,transLogStart(a0) ; load the address into the log to phys table
|
|
move.l D2_totalLeft,transLogCount(a0) ; load the count into the log to phys table
|
|
; trashing A0!
|
|
lea transLogStart(a0), A0 ; pass in the log to phys table
|
|
move.l #1,a1 ; setup the count
|
|
_GetPhysical ; do the translation
|
|
move.l HALactionPB.ioPtr(A4), A0 ; get the ioPtr again (lost it for parameter)
|
|
|
|
tst.w D0 ; well?
|
|
beq.s @fixAddress
|
|
IfDebugStr 'GetPhysical failed in DMA in' ; Aack!
|
|
moveq #dsIOCoreErr, D0
|
|
_SysError
|
|
@fixAddress
|
|
move.l transLogStart(a0),d0 ; get the buffer
|
|
cmp.l d0,a2 ; check to see if the GetPhysical Bug bit us <LW3>
|
|
bne.s @checkAddress ; nope, sometimes GetPhysical doesn't update the
|
|
; logical.addr and logical.cnt fields properly
|
|
add.l transPhyCount(a0),d0 ; find the next logical Address range
|
|
move.l d0,transLogStart(a0) ; stuff it back into the Xlation table
|
|
move.l transPhyCount(a0),d0 ; get the physical count
|
|
sub.l d0,transLogCount(a0) ; and update the count <LW3>
|
|
@checkAddress
|
|
move.l transLogStart(a0),d0 ; get the buffer
|
|
sub.l transPhyCount(a0),d0 ; VM memory manager changed the parameters
|
|
cmp.l d0,A2_userBuffer ; Are we above the start of the physical area?
|
|
blo.s @doGetPhys ; nope, get the pysical address for this range
|
|
cmp.l transLogStart(a0),A2_userBuffer ; are we past the end?
|
|
bhs.s @doGetPhys ; yep, get the physical address for this range
|
|
move.l #$10000,D1_xferSize ; assume a 64K transfer
|
|
move.l transLogStart(a0),d0 ; get the buffer
|
|
sub.l A2_userBuffer,d0 ; find out how much we can transfer into this memory block
|
|
cmp.l d0,D1_xferSize ; use the smaller of 64K and the physical size
|
|
blo.s @gotXferSize ; must be greater than 64K
|
|
move.l d0,D1_xferSize ; use the space we just calculated
|
|
@gotXferSize
|
|
move.b dmaAlignMask+3(A5), D0 ; byte length alignment (000...111)
|
|
not.b D0 ; 111...000
|
|
and.b D0,D1_xferSize ; line align this puppy!
|
|
move.l transLogStart(a0),d0 ; now calculate how far into the buffer we are
|
|
sub.l transPhyCount(a0),d0 ; VM memory manager changed the parameters
|
|
move.l A2_userBuffer,a1
|
|
sub.l d0,a1 ; and find the offset
|
|
move.l transPhyStart(a0),A2_userBuffer ; use the physical address
|
|
add.l a1,A2_userBuffer ; add the offset so we know where to DMA into
|
|
@setupCount
|
|
cmp.l D1_xferSize, D2_totalLeft ; Buffer bigger than amount left?
|
|
bhi.s @1 ; no - xfer size of buffer's worth
|
|
move.l D2_totalLeft, D1_xferSize ; yes - just xfer amount left
|
|
@1
|
|
cmp.b #dmaTypeAMIC, dmaType(A5) ; AMIC?
|
|
bne.s @notAMIC
|
|
|
|
move.l dmaAlignMask(A5), D0 ; get alignment (000…111)
|
|
not.l D0 ; 111…000
|
|
move.l D1_xferSize, D3 ; save xfer_size
|
|
and.l D0, D1_xferSize ; strip away %8 bytes, any left?
|
|
bne.s @notAMIC ; yes-> DMA the big chunks
|
|
; no: move remainder one at a time
|
|
move.l logBuffer(A5), A2_userBuffer ; restore the logical user buffer
|
|
bra.w @alignLpBtm
|
|
@notAMIC
|
|
|
|
;
|
|
; Prime the c96's transfer count registers (2 regs - byte wide)
|
|
;
|
|
IF RECORD_ON THEN
|
|
pea 'rXC-'
|
|
move.l D1_xferSize, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
move.l D1_xferSize, d4 ; d4 <- d1
|
|
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)
|
|
eieio
|
|
|
|
RecCmd $90, 'M',$03
|
|
|
|
;
|
|
; Send DMA_transfer cmd to c96 to Start SCSI Transfer then adjust xferSize (for DMA)
|
|
; to indicate that only words (even #s of bytes) will be transferred from the c96
|
|
; via DMA. If the xferSize is odd, then the c96 will read the odd byte from the bus
|
|
; into its FIFO but it will not assert DREQ for that byte. It will generate an int
|
|
; as soon as the last full word is DMAed out of the c96 and there is a REQ on the
|
|
; bus for the next byte (or next phase).
|
|
;
|
|
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers
|
|
eieio
|
|
IF GROSS_CHECK THEN
|
|
btst #bGrossError, rSTA(a3) ; check for gross error
|
|
beq.s @skipGEdebugger2
|
|
DebugStr 'Gross Error in DataIn_DMA'
|
|
@skipGEdebugger2
|
|
ENDIF
|
|
|
|
;
|
|
; Call the StartDMA routine with parms (scsiDirectionIn, size, buffer)
|
|
;
|
|
IF forPDMProto THEN
|
|
btst #doRealDMARead, dmaFlags(A5)
|
|
bne.s @doRealDMA
|
|
|
|
movem.l A1/A2, -(sp)
|
|
move.l dbug0(A5), A2 ; get logical address of where DMA was supposed to be
|
|
move.l pdmaAddr(A5), A1 ; get pseudo-DMA address
|
|
@fakeDMAloop
|
|
bsr Ck4DREQ
|
|
beq.s @ck4int
|
|
move.w (A1), (A2)+
|
|
move.w (A1), (A2)+
|
|
move.w (A1), (A2)+
|
|
move.w (A1), (A2)+
|
|
bra.s @fakeDMAloop
|
|
@ck4int
|
|
bsr Ck4SCSIInt
|
|
beq.s @fakeDMAloop
|
|
movem.l (sp)+, A1/A2
|
|
|
|
bra.s @doneWithDMA
|
|
@doRealDMA
|
|
ENDIF
|
|
|
|
move.w #true, -(sp) ; direction in
|
|
move.l D1_xferSize, D0
|
|
and.b #$FE, D0 ; c96 will only DMA even #s of bytes
|
|
move.l D0, -(sp) ; size
|
|
btst #noBlockMove,dmaFlags(a5) ; are we doing real DMA?
|
|
beq.s @useCopyBuffer ; nope, use the copy buffer
|
|
move.l a2_userBuffer,-(sp) ; do DMA straight into the user buffer!
|
|
bra.s @sDMA ; start the DMA
|
|
@useCopyBuffer
|
|
move.l physicalCopyBuffer(A5), -(sp) ; buffer is our physical copy buffer
|
|
@sDMA
|
|
jsr ([jvStartDMA,A5]) ; returns A2_SetRegs, A1_ChanlControl
|
|
lea 10(sp), sp ; get parameters off stack
|
|
|
|
;
|
|
; Wait until c96 says it's done (either because it xferred all the bytes and it's
|
|
; ready again or because there was a change of phase (no longer in data_in phase)
|
|
; Once it's done, stop the DMA and see how far it got and BlockMove that many bytes
|
|
; into the user's buffer. The c96 does not interrupt us until AFTER it has DMA'd
|
|
; all of the DMAable bytes. This means that the DMA should be stable (except for a
|
|
; possible final flush that may be in progress). The c96 may have extra byte(s) left
|
|
; over in its FIFO however, and this can be checked for and retrieved directly from
|
|
; the c96.
|
|
;
|
|
bsr.w Wt4SCSIInt ; Wait for intrp
|
|
|
|
jsr ([jvStopReadDMA,A5])
|
|
|
|
@doneWithDMA
|
|
|
|
moveq.l #0, D0 ; prepare for…
|
|
move.b rXCM(A3), D0 ; get remaining xfer count into D0
|
|
lsl.l #8, D0
|
|
move.b rXCL(A3), D0
|
|
|
|
IF RECORD_ON THEN
|
|
pea '-rXC'
|
|
move.l D0, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
sub.l D0, D1_xferSize ; D1 = number of bytes xferred
|
|
|
|
btst #noBlockMove,dmaFlags(a5) ; are we doing real DMA?
|
|
bne.s @afterBM ; yep, no need to do a block move!
|
|
|
|
move.l D1_xferSize, -(sp) ; save D1 --
|
|
;trashing A0
|
|
move.l D1_xferSize, D0 ; D0 = input to BlockMove: size of move
|
|
and.b #$FE, D0 ; c96 only DMA'd even #s of bytes
|
|
move.l logicalCopyBuffer(A5), A0 ; A0 = source: DMA copy buffer
|
|
move.l A2_userBuffer, A1 ; A1 = destination: user's buffer
|
|
_BlockMoveData
|
|
|
|
move.l (sp)+, D1_xferSize ; restore D1 --
|
|
move.l HALactionPB.ioPtr(A4), A0 ; get the ioPtr again (lost it for parameter)
|
|
|
|
@afterBM
|
|
|
|
move.l logBuffer(a5),A2_userBuffer ; restore the logical user buffer
|
|
|
|
;
|
|
; Displace buffer by amount transferred and also decrement totalLeft by that amount
|
|
;
|
|
add.l D1_xferSize, A2_userBuffer ; displace user's buffer by the amount xferred
|
|
sub.l D1_xferSize, D2_totalLeft ; sub done from need to do
|
|
|
|
;
|
|
; Check to see if there is an extra byte in the c96's FIFO; if so, get it
|
|
;
|
|
moveq.l #mFIFOCount, D0 ; use mask to get FIFO flag field
|
|
and.b rFIFOflags(a3), D0 ; how many bytes left in FIFO?
|
|
IF RECORD_ON THEN
|
|
pea 'rFOS'
|
|
move.l D0, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
tst.b D0
|
|
ENDIF
|
|
beq.s @3 ; any bytes? no:go see if we're done
|
|
cmp.b #1, D0 ; if 1, then get it out
|
|
beq.s @2
|
|
IfDebugStr '>1 byte left in the FIFO' ; otherwise, AACK!
|
|
moveq #dsIOCoreErr, D0
|
|
_SysError
|
|
@2 move.b rFIFO(a3), -1(A2_userBuffer) ; put data from FIFO into user's buffer
|
|
IF RECORD_ON THEN
|
|
pea '1byt'
|
|
move.l -4(A2_userBuffer), -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
@3
|
|
tst.l D2_totalLeft
|
|
beq.s @good
|
|
|
|
;
|
|
; We still have more,
|
|
; Make sure that we're still in DataIn phase
|
|
;
|
|
@ckPhase
|
|
moveq.l #iPhaseMsk, d0 ; load mask for phase bits
|
|
and.b rSTA(a3), d0 ; are we in data-in phase?
|
|
cmpi.b #iDataIn, d0 ; data-in phase bits = 001
|
|
bne.s @good
|
|
|
|
cmp.l #$0F, D2_totalLeft ; can we dma anymore?
|
|
bgt.w @loopTop ; yes - do another loop
|
|
|
|
@postDMAalign ; nope, poll the rest of the bytes
|
|
|
|
move.l D2_totalLeft, D3 ; setup alignment count
|
|
bra.w @alignLpBtm ; and go do the alignment
|
|
|
|
@disconnected ; save interrupt regs just like HAL_ISR does
|
|
move.l olderRegsRead(A5), oldestRegsRead(A5)
|
|
move.l oldRegsRead(A5), olderRegsRead(A5)
|
|
move.l newRegsRead(A5), oldRegsRead(A5)
|
|
move.l D5, newRegsRead(A5)
|
|
move.l D5, intRegsRead(A5)
|
|
|
|
@noTransfer
|
|
@good
|
|
@phaseErrAtStart
|
|
@exit
|
|
move.l D2_totalLeft, D1 ; d1 = # of bytes not transferred
|
|
move.b rCF3NormalVal(A5), rCF3(A3) ; return chip to non-t8 mode
|
|
rts ;
|
|
|
|
NAME 'DataIn_DMA'
|
|
|
|
ENDWITH ; SIM_IO
|
|
ENDWITH ; SIMprivFlagsRecord
|
|
ENDWITH
|
|
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
|
|
DataOut_DMA PROC EXPORT ; <SM6> pdw - changed whole routine
|
|
;
|
|
; Register Usage:
|
|
;
|
|
; ———————— On Entry:———————————————————————————————————————————————
|
|
D2_totalLeft EQU D2
|
|
A2_userBuffer EQU A2
|
|
;
|
|
; ———————— On Exit:———————————————————————————————————————————————
|
|
D1_xferSize EQU D1 ; .l =
|
|
;
|
|
;
|
|
; ———————— Internal:———————————————————————————————————————————————
|
|
D3_alignOffset EQU D3 ; .l = offset required for alignment of buffers
|
|
A1_physicalBfr EQU A1
|
|
|
|
MACERevA2 EQU $0941
|
|
MACERevB0 EQU $0940
|
|
|
|
|
|
WITH HALc96GlobalRecord
|
|
WITH SIMprivFlagsRecord
|
|
WITH SIM_IO, SCSIPhase
|
|
|
|
IMPORT DataOut_DMA1x1, SlowWrite96 ;<SM6> pdw thru next
|
|
|
|
IF 1 AND RECORD_ON THEN
|
|
pea 'DMAo' ; EVENT =
|
|
move.l D2, -(sp) ; number of bytes
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
cmpi.b #kDataOutPhase, currentPhase(A5)
|
|
bne @phaseErr ; bra. on phase err
|
|
|
|
;
|
|
; If we are transferring either 1 or 0 bytes, either do a OneByteWrite or noTransfer
|
|
;
|
|
cmp.l #1, D2_totalLeft
|
|
bgt.s @doLots
|
|
bne @noTransfer
|
|
bsr OneByteWrite
|
|
moveq.l #0, D2_totalLeft
|
|
bra @good
|
|
@doLots
|
|
;
|
|
; 1st TIME THRU ----
|
|
;
|
|
; Adjust our DMA buffer addresses on 1st Time Thru to line up with the
|
|
; user's buffer start. That way BlockMove will be able to use MOVE16 for
|
|
; the body of the transfer. Or in the case of DMA the PSC will have a
|
|
; properly aligned buffer
|
|
;
|
|
move.l A2_userBuffer, D3 ; get user's buffer address
|
|
move.w dmaAlignMask+2(A5), D0 ; word-length alignment mask (00…11)
|
|
and.w D0, D3 ; get distance above alignment
|
|
beq.s @doneAligning ; if zero, skip alignment
|
|
eor.w D0, D3 ; number of bytes till alignment (1->E)
|
|
; doesn't require -1 for dbra
|
|
|
|
@align
|
|
;
|
|
; Make sure that we're in DataOut phase between each byte
|
|
;
|
|
move.b (a2)+, rFIFO(a3) ; put the byte
|
|
eieio
|
|
|
|
RecCmd $10, 'M',$05
|
|
move.b #cIOXfer, rCMD(a3) ; load non-DMA transfer cmd & begin 1 byte xfer
|
|
eieio
|
|
;
|
|
; WtForInt
|
|
;
|
|
@noTimeoutWait
|
|
clr.l d5 ;
|
|
move.b rSTA(a3), d5 ; read Status regr
|
|
bpl.s @noTimeoutWait ; ...loop until intrp req is detected
|
|
|
|
move.b D5, D0
|
|
and.b #iPhaseMsk, D0
|
|
move.b D0, currentPhase(A5)
|
|
|
|
swap d5 ;
|
|
move.b rFIFOflags(a3), d5 ;
|
|
lsl.w #8, d5 ;
|
|
move.b rINT(a3), d5 ;
|
|
move.l d5, d0 ; for checking for disconnect
|
|
swap d5 ; d5 = rFOS|rINT|0|rSTA
|
|
|
|
subq.l #1, D2_totalLeft
|
|
beq @good ; if xfer complete - done
|
|
|
|
cmpi.b #kDataOutPhase, currentPhase(A5)
|
|
bne @phaseErr ; bra. on phase err
|
|
@alignLpBtm
|
|
dbra D3, @align ; check to see if we are done aligning
|
|
|
|
@doneAligning
|
|
; load init config. value. Either leaving it at regular or bumping to Threshold-8 mode
|
|
move.b rCF3DMAVal(A5), rCF3(a3)
|
|
|
|
; remember which xfer type we are doing (ParameterBlock)
|
|
; setup buffers the old way if we aren't doing full DMA
|
|
; else setup buffers the new way
|
|
|
|
bclr #noBlockMove,dmaFlags(a5) ; assume that we aren't going to DMA directly to the user's buffer
|
|
|
|
cmp.l minDMAsize(a5),D1_xferSize ; !!! is this a small buffer? (Size should correspond with HALc96PSC.c!)
|
|
ble.s @decidedXferType ; yep, use DMA/Blockmove for small buffers
|
|
|
|
cmp.b #SCSIOldCall,scsiFunctionCode(a0) ; Check to see if it is an old call
|
|
beq.s @decidedXferType ; use the old DMA/Blockmove method for TIBs
|
|
|
|
move.l scsiFlags(a0),d0 ; get the flags field
|
|
andi.l #scsiDataPhys,d0 ; did the client pass in a physical address?
|
|
bne.s @directDMA ; yep, do straight DMA
|
|
|
|
btst #kbUseDblBuffer,SIMprivFlags(a0) ; Are we doing direct DMA for this guy?
|
|
bne.s @decidedXferType ; nope, use DMA/Blockmove for small buffers
|
|
@directDMA
|
|
bset #noBlockMove,dmaFlags(a5) ; remember that we are going directly to the user's buffer
|
|
@decidedXferType
|
|
|
|
;
|
|
; 2nd TIME THRU ---- (and beyond that)
|
|
;
|
|
; If it's not the 1st time thru, we don't have to do any front alignment stuff since
|
|
; it's already aligned.
|
|
;
|
|
@loopTop
|
|
move.l A2_userBuffer,logBuffer(a5) ; save the logical address for later
|
|
IF forPDMProto THEN
|
|
move.l A2_userBuffer, dbug0(A5)
|
|
ENDIF
|
|
btst #noBlockMove,dmaFlags(a5) ; directly to the user's buffer?
|
|
bne.s @newWay
|
|
IF forPDMProto THEN
|
|
move.l logicalCopyBuffer(A5), dbug0(A5)
|
|
ENDIF
|
|
move.l #BFR_SIZE, D1_xferSize ; assume we'll xfer a whole buffer
|
|
bra.w @setupCount
|
|
@newWay
|
|
move.l scsiFlags(a0),d0 ; get the flags field
|
|
andi.l #scsiDataPhys,d0 ; did the client pass in a physical address?
|
|
beq.s @checkAddress ; nope, get the physical address
|
|
move.l #$10000,D1_xferSize ; yep, get them dogies movin!
|
|
bra.s @setupCount
|
|
@doGetPhys
|
|
move.l A2_userBuffer,transLogStart(a0) ; load the address into the log to phys table
|
|
move.l D2_totalLeft,transLogCount(a0) ; load the count into the log to phys table
|
|
; trashing A0
|
|
lea transLogStart(a0),a0 ; pass in the log to phys table
|
|
move.l #1,a1 ; setup the count
|
|
_GetPhysical ; do the translation
|
|
move.l HALactionPB.ioPtr(A4),a0 ; get the ioPtr again (lost it for parameter)
|
|
tst.w D0 ; well?
|
|
beq.s @fixAddress
|
|
IfDebugStr 'GetPhysical failed in DMA out' ; Aack!
|
|
moveq #dsIOCoreErr, D0
|
|
_SysError
|
|
@fixAddress
|
|
move.l transLogStart(a0),d0 ; get the buffer
|
|
cmp.l d0,a2 ; check to see if the GetPhysical Bug bit us <LW3>
|
|
bne.s @checkAddress ; nope, sometimes GetPhysical doesn't update the
|
|
; logical.addr and logical.cnt fields properly
|
|
add.l transPhyCount(a0),d0 ; find the next logical Address range
|
|
move.l d0,transLogStart(a0) ; stuff it back into the Xlation table
|
|
move.l transPhyCount(a0),d0 ; get the physical count
|
|
sub.l d0,transLogCount(a0) ; and update the count <LW3>
|
|
@checkAddress
|
|
move.l transLogStart(a0),d0 ; get the buffer
|
|
sub.l transPhyCount(a0),d0 ; VM memory manager changed the parameters
|
|
cmp.l D0,A2_userBuffer ; Are we above the start of the physical area?
|
|
blo.s @doGetPhys ; nope, get the pysical address for this range
|
|
cmp.l transLogStart(a0),A2_userBuffer ; are we past the end?
|
|
bhs.s @doGetPhys ; yep, get the physical address for this range
|
|
move.l #$10000,D1_xferSize ; assume a 64K transfer
|
|
move.l transLogStart(a0),d0 ; get the buffer
|
|
sub.l A2_userBuffer,d0 ; find out how much we can transfer into this memory block
|
|
cmp.l d0,D1_xferSize ; use the smaller of 64K and the physical size
|
|
blt.s @gotXferSize ; must be greater than 64K
|
|
move.l d0,D1_xferSize ; use the space we just calculated
|
|
@gotXferSize
|
|
and.b #$F0,D1_xferSize ; line align this puppy!
|
|
move.l transLogStart(a0),d0 ; now calculate how far into the buffer we are
|
|
sub.l transPhyCount(a0),d0 ; VM memory manager changed the parameters
|
|
move.l A2_userBuffer,a1
|
|
sub.l d0,a1 ; and find the offset
|
|
move.l transPhyStart(a0),A2_userBuffer ; use the physical address
|
|
add.l a1,A2_userBuffer ; add the offset so we know where to DMA into
|
|
@setupCount
|
|
cmp.l D1_xferSize, D2_totalLeft ; Buffer bigger than amount left?
|
|
bhi.s @1 ; no - xfer size of buffer's worth
|
|
move.l D2_totalLeft, D1_xferSize ; yes - just xfer amount left
|
|
@1
|
|
cmp.b #dmaTypeAMIC, dmaType(A5) ; AMIC?
|
|
bne.s @notAMIC
|
|
move.l dmaAlignMask(A5), D0 ; get alignment (000…111)
|
|
not.l D0 ; 111…000
|
|
move.l D1_xferSize, D3 ; save xfer_size
|
|
and.l D0, D1_xferSize ; strip away %8 bytes, any left?
|
|
bne.s @notAMIC ; yes-> DMA the big chunks
|
|
; no: move remainder one at a time
|
|
move.l logBuffer(A5), A2_userBuffer ; restore the logical user buffer
|
|
bra.w @alignLpBtm
|
|
@notAMIC
|
|
btst #noBlockMove,dmaFlags(a5) ; are we doing real DMA?
|
|
bne.s @afterBM ; yep, no need to do a block move!
|
|
|
|
move.l D1_xferSize, -(sp) ; save D1 --
|
|
|
|
; trashing A0
|
|
move.l D1_xferSize, D0 ; D0 = input to BlockMove: size of move
|
|
move.l A2_userBuffer, A0 ; A0 = source: user's buffer
|
|
move.l logicalCopyBuffer(A5), A1 ; A1 = destination: DMA copy buffer
|
|
|
|
cmp.b #dmaTypeAMIC, dmaType(A5) ; AMIC?
|
|
bne.s @useBlockMove
|
|
_MoveBytesNoDCBZ
|
|
bra.s @bmDone
|
|
@useBlockMove
|
|
_BlockMoveData
|
|
@bmDone
|
|
move.l HALactionPB.ioPtr(A4), A0 ; get the ioPtr again (lost it for parameter)
|
|
|
|
move.l (sp)+, D1_xferSize ; restore D1 --
|
|
|
|
@afterBM
|
|
|
|
;
|
|
; Prime the c96's transfer count registers (2 regs - byte wide)
|
|
;
|
|
IF RECORD_ON THEN
|
|
pea 'rXC-'
|
|
move.l D1_xferSize, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
move.l D1_xferSize, d4 ; d4 <- d1
|
|
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)
|
|
eieio
|
|
|
|
;
|
|
; Send DMA_transfer cmd to c96 to Start SCSI Transfer then adjust xferSize (for DMA)
|
|
; to indicate that only words (even #s of bytes) will be transferred from the c96
|
|
; via DMA. If the xferSize is odd, then the c96 will read the odd byte from the bus
|
|
; into its FIFO but it will not assert DREQ for that byte. It will generate an int
|
|
; as soon as the last full word is DMAed out of the c96 and there is a REQ on the
|
|
; bus for the next byte (or next phase).
|
|
;
|
|
RecCmd $90, 'M',$08
|
|
move.b #cDMAXfer, rCMD(a3) ; load DMA transfer cmd & begin xfers
|
|
eieio
|
|
|
|
;
|
|
; Call the StartDMA routine with parms (scsiDirectionOut, size, buffer)
|
|
;
|
|
IF forPDMProto THEN
|
|
btst #doRealDMAWrite, dmaFlags(A5)
|
|
bne.s @doRealDMA
|
|
|
|
movem.l A1/A2, -(sp)
|
|
move.l dbug0(A5), A2 ; get logical address of where DMA was supposed to be
|
|
move.l pdmaAddr(A5), A1 ; get pseudo-DMA address
|
|
@fakeDMAloop
|
|
bsr Ck4DREQ
|
|
beq.s @ck4int
|
|
move.w (A2)+, (A1)
|
|
move.w (A2)+, (A1)
|
|
move.w (A2)+, (A1)
|
|
move.w (A2)+, (A1)
|
|
bra.s @fakeDMAloop
|
|
@ck4int
|
|
bsr Ck4SCSIInt
|
|
beq.s @fakeDMAloop
|
|
movem.l (sp)+, A1/A2
|
|
|
|
bra.s @doneWithDMA
|
|
@doRealDMA
|
|
ENDIF
|
|
|
|
move.w #false, -(sp) ; false = out
|
|
move.l D1_xferSize, -(sp) ; size
|
|
btst #noBlockMove, dmaFlags(a5) ; are we doing real DMA?
|
|
beq.s @useCopyBuffer ; nope, use the copy buffer
|
|
move.l a2_userBuffer, -(sp) ; do DMA straight from the user buffer!
|
|
bra.s @sDMA ; start the DMA
|
|
@useCopyBuffer
|
|
move.l physicalCopyBuffer(A5), -(sp) ; buffer is our physical copy buffer
|
|
@sDMA
|
|
jsr ([jvStartDMA,A5]) ; returns A2_SetRegs, A1_ChanlControl
|
|
lea 10(sp), sp ; get parameters off stack
|
|
|
|
|
|
bsr.w Wt4SCSIInt ; Wait for intrp
|
|
|
|
jsr ([jvStopWriteDMA,A5])
|
|
|
|
@doneWithDMA
|
|
;
|
|
; Wait until c96 says it's done (either because it xferred all the bytes and it's
|
|
; ready again or because there was a change of phase (no longer in data_in phase)
|
|
; Once it's done, stop the DMA and see how far it got and BlockMove that many bytes
|
|
; into the user's buffer. The c96 does not interrupt us until AFTER it has DMA'd
|
|
; all of the DMAable bytes. This means that the PSC should be stable (except for a
|
|
; possible final flush that may be in progress). The c96 may have an extra byte left
|
|
; over in its FIFO however, and this can be checked for and retrieved directly from
|
|
; the c96.
|
|
;
|
|
moveq.l #0, D0 ; prepare for…
|
|
move.b rXCM(A3), D0 ; get remaining xfer count into D0
|
|
lsl.l #8, D0
|
|
move.b rXCL(A3), D0
|
|
|
|
IF RECORD_ON THEN
|
|
pea '-rXC'
|
|
move.l D0, -(sp)
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
;
|
|
; Adjust xferSize by amount not transferred by PSC and c96
|
|
;
|
|
|
|
move.l logBuffer(a5),A2_userBuffer ; restore the logical user buffer
|
|
sub.l D0, D1_xferSize ; we really didn't transfer them
|
|
|
|
moveq.l #mFIFOCount, D3 ; <SM12> pdw TOP
|
|
and.b int_rFIFOflags(A5), D3 ; if there are any bytes left in c96 FIFO,
|
|
beq.s @skipFlush
|
|
sub.l D3, D1_xferSize ; we really didn't transfer them and
|
|
|
|
RecCmd $01, 'M',$0c
|
|
move.b #cFlushFIFO, rCMD(A3) ; we should flush them out of there <SM15> pdw
|
|
eieio
|
|
@skipFlush ; <SM12> pdw BOT
|
|
|
|
;
|
|
; Displace buffer by amount transferred and also decrement totalLeft by that amount
|
|
;
|
|
add.l D1_xferSize, A2_userBuffer ; displace user's buffer by the amount xferred
|
|
sub.l D1_xferSize, D2_totalLeft ; sub done from need to do
|
|
beq.s @good
|
|
|
|
;
|
|
; We still have more,
|
|
; Make sure that we're still in DataIn phase
|
|
;
|
|
@ckPhase
|
|
cmpi.b #kDataOutPhase, currentPhase(A5)
|
|
bne.s @phaseErr ; bra. on phase err
|
|
|
|
cmp.l #$0F,D2_totalLeft ; can we dma anymore?
|
|
ble.s @postDMAalign ; nope, poll the rest of the bytes
|
|
|
|
bra.w @loopTop ; bra. if still in phase
|
|
|
|
@postDMAalign
|
|
move.l D2_totalLeft,d3 ; setup alignment count
|
|
bra.w @align ; and go do the alignment
|
|
|
|
@bytesXferd
|
|
@disconnected
|
|
@noTransfer
|
|
@good
|
|
@exit
|
|
@phaseErr
|
|
@badFWrite
|
|
move.l D2_totalLeft, D1 ; d1 = # of bytes not transferred
|
|
move.b rCF3NormalVal(A5), rCF3(A3) ; return chip to non-t8 mode
|
|
rts ;
|
|
|
|
ENDWITH
|
|
ENDWITH ; SIM_IO
|
|
ENDWITH ; SIMprivFlagsRecord
|
|
|
|
RTSNAME 'DataOut_DMA'
|
|
|
|
|
|
|
|
DataOut_DMA1x1 PROC EXPORT ; <SM6> pdw - changed whole routine
|
|
|
|
WITH HALc96GlobalRecord
|
|
|
|
IF 1 AND RECORD_ON THEN
|
|
pea '1x1o' ; EVENT =
|
|
move.l D2, -(sp) ; number of bytes
|
|
bsr RecordEvent
|
|
addq.l #8, sp
|
|
ENDIF
|
|
|
|
moveq.l #iPhaseMsk, d0 ; load mask for phase bits
|
|
and.b rSTA(a3), d0 ; are we in data-in phase?
|
|
;; cmpi.b #iDataOut, d0 ; data-out phase bits = 000
|
|
bne.s @phaseErr ; bra. on phase err
|
|
|
|
;
|
|
; If we are transferring either 1 or 0 bytes, either do a OneByteWrite or noTransfer
|
|
;
|
|
cmp.l #1, D2
|
|
bgt.s @doLots
|
|
bne.s @noTransfer
|
|
bsr OneByteWrite
|
|
moveq.l #0, D1 ; no more bytes to transfer <SM7> pdw
|
|
bra.s @good
|
|
@doLots
|
|
move.l d2, d3 ;
|
|
swap d3 ; d3.w:d2.w = total#bytes to xfer
|
|
cmp.w D0, D0 ; make sure that we're .eq.
|
|
bra.s @LpWriteBtm
|
|
@LpWriteTop
|
|
cmpi.b #iDataOut, D0 ; data-in phase bits = 001
|
|
bne.s @phaseErr ; bra. on phase err
|
|
|
|
move.b (a2)+, rFIFO(a3) ; put a byte
|
|
eieio
|
|
|
|
RecCmd $10, 'M',$0e
|
|
move.b #cIOXfer, rCMD(a3) ; load non-DMA transfer cmd & begin 1 byte xfer
|
|
eieio
|
|
|
|
; bsr.w Wt4SCSIInt ; Wait for intrp
|
|
@1
|
|
move.b rSTA(a3), D0 ; int?
|
|
bpl.s @1
|
|
and.b #iPhaseMsk, d0 ; and mask for phase bits
|
|
move.b D0, currentPhase(A5)
|
|
btst.b #bDisconnected, rINT(a3)
|
|
@LpWriteBtm
|
|
dbne d2, @LpWriteTop ; d2 = low word of count
|
|
dbne d3, @LpWriteTop ; d3 = high word of count
|
|
|
|
swap d3
|
|
move.w d2, d3
|
|
moveq.l #1, d1
|
|
add.l d3, d1
|
|
|
|
|
|
@disconnected
|
|
@noTransfer
|
|
@good ; d1 = # of bytes transferred
|
|
rts ;
|
|
|
|
|
|
@phaseErr
|
|
|
|
@bytesXferd ;
|
|
swap d3 ; calculate bytes left to transfer
|
|
move.w d2, d3 ; get low order word
|
|
move.l d3, d1
|
|
@badFWrite
|
|
rts ;
|
|
|
|
|
|
NAME 'DataOut_DMA1x1'
|
|
|
|
ENDWITH
|
|
ENDP
|
|
|
|
|
|
END
|
|
|