mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-25 09:30:50 +00:00
320 lines
9.9 KiB
Plaintext
320 lines
9.9 KiB
Plaintext
|
;
|
||
|
; File: HALc96GC.a
|
||
|
;
|
||
|
; Contains: Grand Central SCSI HBA
|
||
|
;
|
||
|
; Written by: Craig Prouse
|
||
|
;
|
||
|
; Copyright: © 1993 by Apple Computer, Inc., all rights reserved.
|
||
|
;
|
||
|
; Change History (most recent first):
|
||
|
;
|
||
|
; <SM2> 11/19/93 chp Add primitives for clearing, enabling, and disabling SCSI IRQ.
|
||
|
; Add a primitive for testing SCSI IE.
|
||
|
; <SMG2> 10/26/93 chp Adjust for changes in DBDMA and Grand Central header files.
|
||
|
;
|
||
|
;
|
||
|
|
||
|
|
||
|
case on
|
||
|
|
||
|
print push,off
|
||
|
include 'DBDMA.a'
|
||
|
include 'ACAM.a'
|
||
|
include 'HALc96equ.a'
|
||
|
print pop
|
||
|
|
||
|
machine mc68020
|
||
|
|
||
|
|
||
|
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
; StartGC:
|
||
|
;
|
||
|
; In: A5 pointer to HALc96GlobalRecord
|
||
|
; (SP) stack-based arguments
|
||
|
;
|
||
|
; Initiate DMA.
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
|
||
|
StartGC proc export
|
||
|
|
||
|
saveRegs reg d1-d3
|
||
|
|
||
|
maxAtomicCount equ $FFF0 ; maximum atomic DMA transfer count
|
||
|
|
||
|
StackFrame record {a6Link},decrement
|
||
|
dirRead ds.w 1 ; direction is read (16-bit Boolean)
|
||
|
byteCount ds.l 1 ; number of bytes to transfer
|
||
|
bufferAddr ds.l 1 ; source/destination buffer for transfer
|
||
|
rtsAddr ds.l 1
|
||
|
a6Link ds.l 1
|
||
|
localSize equ *
|
||
|
endr
|
||
|
|
||
|
with HALc96GlobalRecord, StackFrame
|
||
|
|
||
|
link a6,#localSize
|
||
|
movem.l saveRegs,-(sp)
|
||
|
|
||
|
; A0 is set initially to the address of the first channel command descriptor.
|
||
|
|
||
|
movea.l cclLogicalAddr(a5),a0 ; pointer to DBDMA command list buffer
|
||
|
|
||
|
; D3 will contain the command word for a list of input or output channel commands.
|
||
|
|
||
|
tst.w dirRead(a6)
|
||
|
bne.b @input
|
||
|
@output move.w #OUTPUT_MORE,d3
|
||
|
bra.b @ioCommon
|
||
|
@input move.w #INPUT_MORE,d3
|
||
|
|
||
|
; A single DB-DMA channel command can transfer at most $FFFF bytes since the count
|
||
|
; field is 16 bits. The 53C9x can only DMA an even number of bytes, producing an
|
||
|
; effective limit of $FFFE bytes. For the sake of roundness, this CCL shall not
|
||
|
; contain any commands for more than $FFF0 bytes. The channel command list is
|
||
|
; generated using as many descriptors as necessary to satisfy the request. The CCL
|
||
|
; buffer is one physical page (8K) in length, allowing for up to 511 data transfer
|
||
|
; descriptors, or nearly 32 MB in a single request. There is no range checking.
|
||
|
|
||
|
@ioCommon
|
||
|
move.l #maxAtomicCount,d0
|
||
|
movea.l bufferAddr(a6),a1 ; DMA address in A1
|
||
|
move.l byteCount(a6),d2 ; remaining DMA count in D2
|
||
|
bra.b @loopTest
|
||
|
|
||
|
@partialIOCmd swap d0
|
||
|
move.w d3,d0 ; command in high word of D0
|
||
|
swap d0 ; count in low word of D0
|
||
|
_MakeCCDescriptor
|
||
|
adda.w #DBDMADescriptor.size,a0
|
||
|
|
||
|
move.l #maxAtomicCount,d0
|
||
|
adda.l d0,a1 ; increment transfer address
|
||
|
sub.l d0,d2 ; decrement remaining transfer count
|
||
|
|
||
|
@loopTest beq.b @stopCmd ; generate STOP immediately when count = 0
|
||
|
cmp.l d0,d2
|
||
|
bhi.b @partialIOCmd
|
||
|
|
||
|
@lastIOCmd move.w d3,d0
|
||
|
swap d0 ; command in high word of D0
|
||
|
move.w d2,d0 ; remaining count in low word of D0
|
||
|
_MakeCCDescriptor
|
||
|
adda.w #DBDMADescriptor.size,a0
|
||
|
|
||
|
@stopCmd move.l #(STOP<<16) | $0000,d0 ; stop command / count field is reserved
|
||
|
lea 0,a1 ; address field is reserved
|
||
|
_MakeCCDescriptor
|
||
|
|
||
|
; Point the DMA hardware at the new CCL.
|
||
|
|
||
|
movea.l dmaCntrlAddr(a5),a0 ; pointer to SCSIx DBDMAChannelRegisters in A0
|
||
|
move.l cclPhysicalAddr(a5),d0 ; pointer to channel command list in D0
|
||
|
_SetCommandPtr
|
||
|
|
||
|
; Reset anything wrong with the channel status and start it running.
|
||
|
|
||
|
move.l # kdbdmaSetRun |\
|
||
|
kdbdmaClrPause |\
|
||
|
kdbdmaClrHalted |\
|
||
|
kdbdmaClrDead |\
|
||
|
kdbdmaSetActive, d0
|
||
|
_SetChannelControl ; A0 still points to DBDMAChannelRegisters
|
||
|
|
||
|
movem.l (sp)+,saveRegs
|
||
|
unlk a6
|
||
|
rts
|
||
|
|
||
|
endwith
|
||
|
endproc
|
||
|
|
||
|
|
||
|
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
; StopGCRead:
|
||
|
; StopGCWrite:
|
||
|
; Wt4GCComplete:
|
||
|
;
|
||
|
; In: A5 pointer to HALc96GlobalRecord
|
||
|
; Out: D0.L residual count
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
|
||
|
StopGCDMA func entry
|
||
|
export StopGCRead, StopGCWrite, Wt4GCComplete
|
||
|
|
||
|
saveRegs reg d1/d2
|
||
|
|
||
|
with HALc96GlobalRecord
|
||
|
|
||
|
StopGCRead
|
||
|
StopGCWrite
|
||
|
movea.l dmaCntrlAddr(a5),a0 ; pointer to SCSIx DBDMAChannelRegisters in A0
|
||
|
move.l #kdbdmaClrRun,d0
|
||
|
_SetChannelControl ; abort the CCL
|
||
|
|
||
|
Wt4GCComplete
|
||
|
movea.l dmaCntrlAddr(a5),a0 ; pointer to SCSIx DBDMAChannelRegisters in A0
|
||
|
@waitInactive _GetChannelStatus ; wait for last status writeback
|
||
|
andi.l #kdbdmaActive,d0
|
||
|
bne.b @waitInactive
|
||
|
|
||
|
; For better or for worse, channel command execution has stopped. It is now time to
|
||
|
; calculate the residual count. This is just a little bit complicated because it is
|
||
|
; not known exactly how many command descriptors in the list completed execution.
|
||
|
|
||
|
movem.l saveRegs,-(sp)
|
||
|
|
||
|
moveq #0,d2 ; accumulate residual count in D2
|
||
|
movea.l cclLogicalAddr(a5),a0 ; this is where CCL execution started
|
||
|
|
||
|
@nextDescriptor
|
||
|
_GetCCOperation
|
||
|
cmpi.l #(STOP<<16) | $0000,d0 ; is this the end-of-list?
|
||
|
beq.b @done
|
||
|
|
||
|
move.l d0,d1 ; save the request count
|
||
|
_GetCCResult
|
||
|
tst.l d0 ; did a status writeback occur?
|
||
|
bne.b @addResidual ; yes, use residual count field
|
||
|
move.l d1,d0 ; no, use request count field
|
||
|
|
||
|
@addResidual and.l #$0000FFFF,d0 ; mask off xferStatus
|
||
|
add.l d0,d2 ; accumulate residual count
|
||
|
|
||
|
adda.w #DBDMADescriptor.size,a0 ; increment to next descriptor
|
||
|
bra.b @nextDescriptor
|
||
|
|
||
|
@done
|
||
|
move.l d2,d0 ; move total residual count to D0 result
|
||
|
movem.l (sp)+,saveRegs
|
||
|
rts
|
||
|
|
||
|
endwith
|
||
|
endfunc
|
||
|
|
||
|
|
||
|
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
; ClearGCSCSIIRQ:
|
||
|
;
|
||
|
; In: A5 pointer to HALc96GlobalRecord
|
||
|
;
|
||
|
; This routine may not change any registers.
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
|
||
|
ClearGCSCSIIRQ proc entry
|
||
|
|
||
|
intClearOffset equ gcInterruptClear - gcInterruptMask
|
||
|
|
||
|
with HALc96GlobalRecord
|
||
|
|
||
|
align 8
|
||
|
export ClearGCSCSI0IRQ
|
||
|
ClearGCSCSI0IRQ:
|
||
|
ori.l #1 << gcifDevSCSI0,([intEnableSCSIAddr,a5],intClearOffset)
|
||
|
rts
|
||
|
|
||
|
align 8
|
||
|
export ClearGCSCSI1IRQ
|
||
|
ClearGCSCSI1IRQ:
|
||
|
ori.l #1 << gcifDevSCSI1,([intEnableSCSIAddr,a5],intClearOffset)
|
||
|
rts
|
||
|
|
||
|
endwith
|
||
|
endproc
|
||
|
|
||
|
|
||
|
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
; EnableGCSCSIIRQ:
|
||
|
;
|
||
|
; In: A5 pointer to HALc96GlobalRecord
|
||
|
;
|
||
|
; This routine may not change any registers.
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
|
||
|
EnableGCSCSIIRQ proc entry
|
||
|
|
||
|
with HALc96GlobalRecord
|
||
|
|
||
|
align 8
|
||
|
export EnableGCSCSI0IRQ
|
||
|
EnableGCSCSI0IRQ:
|
||
|
ori.l #1 << gcifDevSCSI0,([intEnableSCSIAddr,a5])
|
||
|
rts
|
||
|
|
||
|
align 8
|
||
|
export EnableGCSCSI1IRQ
|
||
|
EnableGCSCSI1IRQ:
|
||
|
ori.l #1 << gcifDevSCSI1,([intEnableSCSIAddr,a5])
|
||
|
rts
|
||
|
|
||
|
endwith
|
||
|
endproc
|
||
|
|
||
|
|
||
|
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
; DisableGCSCSIIRQ:
|
||
|
;
|
||
|
; In: A5 pointer to HALc96GlobalRecord
|
||
|
;
|
||
|
; This routine may not change any registers.
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
|
||
|
DisableGCSCSIIRQ proc entry
|
||
|
|
||
|
with HALc96GlobalRecord
|
||
|
|
||
|
align 8
|
||
|
export DisableGCSCSI0IRQ
|
||
|
DisableGCSCSI0IRQ:
|
||
|
andi.l #~(1 << gcifDevSCSI0),([intEnableSCSIAddr,a5])
|
||
|
rts
|
||
|
|
||
|
align 8
|
||
|
export DisableGCSCSI1IRQ
|
||
|
DisableGCSCSI1IRQ:
|
||
|
andi.l #~(1 << gcifDevSCSI1),([intEnableSCSIAddr,a5])
|
||
|
rts
|
||
|
|
||
|
endwith
|
||
|
endproc
|
||
|
|
||
|
|
||
|
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
; TestGCSCSIIE:
|
||
|
;
|
||
|
; In: A5 pointer to HALc96GlobalRecord
|
||
|
; Out: CCR Z flag indicates state of the SCSI interrupt enable
|
||
|
;
|
||
|
; This routine may use D0.
|
||
|
; ……………………………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
|
||
|
TestGCSCSIIE proc entry
|
||
|
|
||
|
with HALc96GlobalRecord
|
||
|
|
||
|
align 8
|
||
|
export TestGCSCSI0IE
|
||
|
TestGCSCSI0IE:
|
||
|
move.l #1 << gcifDevSCSI0,d0
|
||
|
and.l ([intEnableSCSIAddr,a5]),d0
|
||
|
rts
|
||
|
|
||
|
align 8
|
||
|
export TestGCSCSI1IE
|
||
|
TestGCSCSI1IE:
|
||
|
move.l #1 << gcifDevSCSI1,d0
|
||
|
and.l ([intEnableSCSIAddr,a5]),d0
|
||
|
rts
|
||
|
|
||
|
endwith
|
||
|
endproc
|
||
|
|
||
|
|
||
|
|
||
|
end
|