mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
4325cdcc78
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.
1149 lines
39 KiB
Plaintext
1149 lines
39 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
|
|
|