mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-08-29 08:29:03 +00:00
1392 lines
47 KiB
Plaintext
1392 lines
47 KiB
Plaintext
;
|
|
; File: ADBPrimitives.a
|
|
;
|
|
; Contains: low-level hardware-dependent ADB and DebugUtil routines
|
|
;
|
|
; Written by: Steve Christensen
|
|
;
|
|
; Copyright: © 1991-1993 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; This file is used in these builds: ROM
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM9> 11/9/93 KW added some eieioSTP macros. Only expands for CygnusX1 ROM
|
|
; <SM8> 8/4/93 JDR private sound defines were moved to SoundPrivate.a
|
|
; <SM7> 6/14/93 kc Roll in Ludwig.
|
|
; <LW2> 1/21/93 KW CudaDebugEnter should not send PDMSuspend command...should just
|
|
; fall through to EgretDebugEnter. CudaDebugExit should send
|
|
; PDMDebugContinue instead of PDMContinue. Bug fix #1049224
|
|
; <SM6> 11/23/92 SWC Put the build conditionals back in. Added a table for Cuda and
|
|
; fixed the Cuda routines so they don't require any Universal
|
|
; checks (the whole point of using primitives).
|
|
; <SM5> 8/26/92 kc Roll in Horror changes.
|
|
; <H4> 8/25/92 BG Changed VIAStartReq at @waitforinput so that the code waits for
|
|
; at least 8.8µs before switching the direction of the shift
|
|
; register (output to input) to guarantee that we don't outrun the
|
|
; ADB micro's ability to respond. Removed <H3>.
|
|
; <H3> 7/10/92 BG Added a temporary KLUDGE to ViaDebugPoll to allow typing in
|
|
; MacsBug/etc. to function 'normally' again. See the comments for
|
|
; more details.
|
|
; <H2> 5/3/92 BG Removed references to hasOrwell2, since it is now superfluous to
|
|
; hasOrwell.
|
|
; <SM4> 07-14-92 jmp Added a changed to make typing MacsBug work a little better on
|
|
; Quadra 700s until GR finds a better way to do this.
|
|
; <SM3> 7/10/92 mal Changed include from ApplDeskBusPriv.a to AppleDeskBusPriv.a.
|
|
; <SM2> 5/28/92 KW (GS,P3) Added suspend/continue PDM to the Debug util code.
|
|
; <1> 5/17/92 kc first checked in
|
|
; <SM0> 5/2/92 kc Roll in Horror. Comments follow:
|
|
; <H1> 4/3/92 SWC Adding this file into the build.
|
|
|
|
|
|
PRINT OFF
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'HardwarePrivateEqu.a'
|
|
INCLUDE 'SoundPrivate.a'
|
|
INCLUDE 'UniversalEqu.a'
|
|
IF PwrMgrADB THEN
|
|
INCLUDE 'PowerPrivEqu.a'
|
|
ENDIF
|
|
IF hasEgret THEN
|
|
INCLUDE 'EgretEqu.a'
|
|
ENDIF
|
|
IF IopADB THEN
|
|
INCLUDE 'IopEqu.a'
|
|
ENDIF
|
|
INCLUDE 'AppleDeskBusPriv.a'
|
|
INCLUDE 'IOPrimitiveEqu.a'
|
|
PRINT ON
|
|
PRINT NOMDIR
|
|
MACHINE MC68020
|
|
|
|
NoIntMask EQU $0700 ; all ints disabled on all machines
|
|
|
|
|
|
|
|
ADBPrimitives PROC EXPORT
|
|
|
|
IMPORT ImplicitRequestDone, ExplicitRequestDone
|
|
|
|
WITH ADBVars,ADBMsg
|
|
|
|
|
|
;————————————————————————————————————————————————————————————————————————————————————————
|
|
;
|
|
; ADB primitives vector table
|
|
;
|
|
; Tables pointed to by the universal ProductInfo record (ADBDebugUtilPtr) for low-level
|
|
; hardware-dependent ADB routines. There should be a table for each supported
|
|
; ProductInfo.
|
|
|
|
|
|
IF ViaADB THEN
|
|
EXPORT ViaADBTable
|
|
DC.W (VIATableEnd-ViaADBTable)/4 ; number of entries
|
|
ViaADBTable
|
|
DC.L VIAInitADB-ViaADBTable ; ADB initialization
|
|
DC.L 0 ; not used
|
|
DC.L 0 ; not used
|
|
DC.L 0 ; not used
|
|
DC.L VIADebugPoll-ViaADBTable ; DebugUtil ADB polling
|
|
DC.L 0 ; not used
|
|
VIATableEnd
|
|
ENDIF
|
|
|
|
|
|
IF PwrMgrADB THEN
|
|
EXPORT PMgrADBTable
|
|
DC.W (PMGRTableEnd-PMgrADBTable)/4 ; number of entries
|
|
PMgrADBTable
|
|
DC.L PMgrInitADB-PMgrADBTable ; ADB initialization
|
|
DC.L PMgrEnableKbdNMI-PMgrADBTable ; not used
|
|
DC.L 0 ; not used
|
|
DC.L 0 ; not used
|
|
DC.L PMgrDebugPoll-PMgrADBTable ; DebugUtil ADB polling
|
|
DC.L 0 ; not used
|
|
PMGRTableEnd
|
|
ENDIF
|
|
|
|
|
|
IF hasEgret THEN
|
|
EXPORT EgretADBTable
|
|
DC.W (EgretTableEnd-EgretADBTable)/4 ; number of entries
|
|
EgretADBTable
|
|
DC.L EgretInitADB-EgretADBTable ; ADB initialization
|
|
DC.L 0 ; not used
|
|
DC.L EgretDebugEnter-EgretADBTable ; DebugUtil enter
|
|
DC.L EgretDebugExit-EgretADBTable ; DebugUtil exit
|
|
DC.L EgretDebugPoll-EgretADBTable ; DebugUtil ADB polling
|
|
DC.L 0 ; not used
|
|
EgretTableEnd
|
|
|
|
EXPORT CudaADBTable
|
|
DC.W (CudaTableEnd-CudaADBTable)/4 ; number of entries
|
|
CudaADBTable
|
|
DC.L EgretInitADB-CudaADBTable ; ADB initialization
|
|
DC.L 0 ; not used
|
|
DC.L CudaDebugEnter-CudaADBTable ; DebugUtil enter
|
|
DC.L CudaDebugExit-CudaADBTable ; DebugUtil exit
|
|
DC.L EgretDebugPoll-CudaADBTable ; DebugUtil ADB polling
|
|
DC.L 0 ; not used
|
|
CudaTableEnd
|
|
ENDIF
|
|
|
|
|
|
IF IopADB THEN
|
|
EXPORT IOPADBTable
|
|
DC.W (IOPTableEnd-IOPADBTable)/4 ; number of entries
|
|
IOPADBTable
|
|
DC.L IOPInitADB-IOPADBTable ; ADB initialization
|
|
DC.L 0 ; not used
|
|
DC.L IOPRunKBD-IOPADBTable ; DebugUtil enter
|
|
DC.L 0 ; not used
|
|
DC.L IOPRunKBD-IOPADBTable ; DebugUtil ADB polling
|
|
DC.L 0 ; not used
|
|
IOPTableEnd
|
|
|
|
IF hasOrwell THEN ; <H2>
|
|
EXPORT QuadraADBTable
|
|
DC.W (QuadraADBTableEnd-QuadraADBTable)/4; number of entries
|
|
QuadraADBTable
|
|
DC.L IOPInitADB-QuadraADBTable ; ADB initialization
|
|
DC.L 0 ; not used
|
|
DC.L IOPRunKBD-QuadraADBTable ; DebugUtil enter
|
|
DC.L 0 ; not used
|
|
DC.L QuadraDebugPoll-QuadraADBTable ; DebugUtil ADB polling
|
|
DC.L QuadraCheckSecure-QuadraADBTable ; check if keyswitch is in SECURE position
|
|
QuadraADBTableEnd
|
|
ENDIF
|
|
ENDIF
|
|
|
|
|
|
|
|
IF ViaADB THEN
|
|
;••••••••••••••••••••••••••••••••••••••••• VIA ••••••••••••••••••••••••••••••••••••••••••
|
|
|
|
IMPORT RunADBRequest
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: VIAInitADB
|
|
;
|
|
; Inputs: A3 - pointer to ADBBase
|
|
;
|
|
; Outputs:
|
|
;
|
|
; Trashes: A0
|
|
;
|
|
; Function: initializes the ADB Manager for VIA-based ADB
|
|
;________________________________________________________________________________________
|
|
|
|
VIAInitADB LEA FDBShiftInt,A0 ; get the address of the interrupt handler
|
|
MOVE.L A0,Lvl1DT+(4*ifSR) ; and install it as the SR interrupt receiver
|
|
LEA VIAStartReq,A0 ; setup the procedure to start an ADB request
|
|
MOVE.L A0,StartReqProc(A3)
|
|
MOVEA.L VIA,A0 ; point to the VIA1 registers
|
|
ORI #NoIntMask,SR ; mask out interrupts
|
|
eieioSTP
|
|
MOVE.B #(1<<ifIRQ)|\ ; enable the shift register interrupt
|
|
(1<<ifSR),vIER(A0)
|
|
eieioSTP
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: VIAStartReq
|
|
;
|
|
; Inputs: A2 - pointer to transmit data buffer
|
|
; A3 - pointer to ADBBase
|
|
; D2 - number of bytes of transmit data
|
|
; D3 - command byte (bits 0-7) + implicit flag (bit 31)
|
|
;
|
|
; Outputs: A1 - pointer to base of VIA1
|
|
; A3 - pointer to ADBBase
|
|
;
|
|
; Trashes: D0,D1,D3
|
|
;
|
|
; Function: starts an ADB request using the VIA interface to the ADB transceiver processor
|
|
;________________________________________________________________________________________
|
|
|
|
VIAStartReq MOVEA.L VIA,A1 ; point to VIA1
|
|
BSET #fDBBusy,FDBAuFlag(A3) ; remember that we are busy
|
|
BNE.S @AlreadyBusy ; -> already busy, so do nothing and return
|
|
|
|
TST.L D3 ; is this an implicit request?
|
|
BPL.S @Explicit ; -> nope
|
|
|
|
; send an implicit command (auto / SRQ polling), no data needs to be sent
|
|
|
|
@Implicit MOVE.B PollAddr(A3),D3 ; get the auto/SRQ polling address
|
|
LSL.B #4,D3
|
|
ORI.B #talkCmd+0,D3 ; and make it a Talk R0 command
|
|
BSR @SendCmd ; send out the command byte
|
|
BEQ.S @AutoReply ; -> see if prior auto poll data returned instead
|
|
|
|
MOVE.B fDBCmd(A3),pollCmd(A3) ; remember the command byte
|
|
BSR.S @StartAutoPoll ; start auto polling
|
|
BTST #fDBQEmpty,FDBFlag(A3) ; see if anything queued
|
|
BNE.S @Idle ; -> no, just wait for auto poll data
|
|
|
|
; We have just changed from state 0 to state 3. If a command is in the queue, we will
|
|
; want to change back to state 0, and send a new command. We have to give the xcvr
|
|
; processor time to recognize the state change into state 3 before we change back to
|
|
; state 0, otherwise it will be out of sync.
|
|
|
|
MOVE.W TimeViaDB,D0 ; get 1ms VIA loop time constant
|
|
; LSR.W #4,D0 ; 1ms/16 = 62.5µs
|
|
;•••• STP ••• eric -- let's double it??
|
|
lsr.w #2,d0 ; 1ms/16 = 62.5µs
|
|
@Delay
|
|
eieioSTP
|
|
BTST #0,vBufB(A1) ; timing based on BTST loop, we don't care
|
|
eieioSTP
|
|
DBRA D0,@Delay ; wait at least 50µs for state change to occur
|
|
BSR.S @Idle ; mark us idle
|
|
BRA.L RunADBRequest ; go run the next request in the queue
|
|
|
|
@Idle BCLR #fDBBusy,FDBAuFlag(A3) ; allow explicit cmds to interrupt auto polling
|
|
@AlreadyBusy
|
|
RTS ; if not, just let auto polling continue
|
|
|
|
@StartAutoPoll
|
|
MOVEQ #(1<<vFDesk1)|\
|
|
(1<<vFDesk2),D1 ; change from state 0 to state 3
|
|
BSR @waitForInput ; start auto polling, wait for a reply
|
|
ORI.B #(1<<fDBAPoll)|\ ; indicate that auto poll data returned
|
|
(1<<fDBBusy),FDBAuFlag(A3) ; auto poll found something, we're busy again
|
|
MOVEQ #(1<<vFDesk2),D1 ; change from state 3 to state 1
|
|
BRA.S @getReply ; join common code to get reply
|
|
|
|
@explicit MOVEQ #maskADBCmd,D0 ; setup to extract command
|
|
AND.B D3,D0 ; clear addr and reg
|
|
SUBQ.B #listenCmd,D0 ; check for listen command
|
|
BEQ @listen ; explicit listen is special case
|
|
|
|
; send an explicit command (other than listen), no data needs to be sent
|
|
|
|
BSR.S @sendCmd ; send out the command byte
|
|
BNE.S @explicitReply ; see if auto poll data returned instead
|
|
@autoReply BSET #fDBAPoll,FDBAuFlag(A3) ; indicate that auto poll data returned
|
|
MOVE.B pollCmd(A3),fDBCmd(A3) ; poll command is command that is completing
|
|
@explicitReply
|
|
|
|
MOVEQ #(1<<vFDesk1),D1 ; change from state 0 to state 1
|
|
@getReply BSR.S @waitForInput ; wait for the first byte
|
|
BNE.S @noTimeout ; see if timeout occured
|
|
BSET #fDBNoReply,FDBAuFlag(A3) ; indicate that no reply data was returned
|
|
@noTimeout CLR.B fDBCnt(A3) ; indicate buffer empty
|
|
|
|
BSR.W @getNextByte ; wait for the second byte
|
|
BNE.S @noSRQ ; see if SRQ occured
|
|
BSET #fDBSRQ,FDBAuFlag(A3) ; indicate that no service request was returned
|
|
@noSRQ
|
|
|
|
@fetchLoop BSR.W @getNextByte ; wait for another byte
|
|
BEQ.S @fetchDone ; exit if end of data reached
|
|
CMPI.B #8,fDBCnt(A3) ; see if end of buffer reached
|
|
BLO.S @fetchLoop ; keep fetching until end of data
|
|
@fetchDone BTST #fDBNoReply,FDBAuFlag(A3) ; see if buffer data is valid
|
|
SEQ D0 ; $FF if data is valid, $00 if no reply
|
|
AND.B D0,fDBCnt(A3) ; set count to zero if timeout
|
|
BRA VIAReqDone
|
|
|
|
|
|
@sendCmd ANDI.B #$FF-(\
|
|
(1<<fDBAPoll)|\ ; clear auto poll reply flag
|
|
(1<<fDBSRQ)|\ ; clear SRQ active in reply flag
|
|
(1<<fDBNoReply)),\ ; clear reply timeout flag
|
|
FDBAuFlag(A3) ; clear the flags
|
|
MOVE.W SR,D0 ; save int mask
|
|
ORI #NoIntMask,SR ; disable ALL interrupts
|
|
|
|
MOVEQ #(1<<vFDesk2)+\
|
|
(1<<vFDesk1),D1 ; mask the current state
|
|
eieioSTP
|
|
AND.B vBufB(A1),D1
|
|
CMPI.B #(1<<vFDesk2)+\
|
|
(1<<vFDesk1),D1 ; are we in state 3?
|
|
BNE.S @SendCont ; no, procede as usual
|
|
eieioSTP
|
|
BTST #vFDBInt,vBufB(a1) ; yes, test the FDBInt~ status
|
|
eieioSTP
|
|
BEQ.S @SendExit ; asserted, xcvr already clocking autopoll data
|
|
; exit (wait for autopoll to complete)
|
|
|
|
@SendCont
|
|
eieioSTP
|
|
ORI.B #$1C,vACR(a1) ; set SR to shift-out with ext clk
|
|
eieioSTP
|
|
MOVE.B D3,vSR(a1) ; load shift reg with cmd, start shifting
|
|
eieioSTP
|
|
MOVE.B D3,fDBCmd(A3) ; save the command
|
|
eieioSTP
|
|
ANDI.B #-1-(1<<vFDesk2)-\
|
|
(1<<vFDesk1),vBufB(A1) ; force state bits to zero
|
|
eieioSTP
|
|
@SendExit MOVE.L (SP)+,ShiftIntResume(A3); save resume address
|
|
MOVE D0,SR ; restore interrupt mask
|
|
RTS ; return to callers caller, wait for interrupt
|
|
|
|
|
|
@waitForInput
|
|
; Shouldn't do the change to shift-in mode til rising edge of ADB clock, which could <H4> thru next <H4>
|
|
; be a max. of 8.8µs after getting the shift register interrupt from sending out the
|
|
; command byte. These TSTs aren't to actually test a condition - they are to wait
|
|
; the appropriate amount of time before changing mode. We have already done 2 accesses
|
|
; to the VIA, so we have 2.4µs of time already accounted for.
|
|
eieioSTP
|
|
tst.b vBufB(A1) ; wait for ADB xcvr to have a rising edge (~8.8µs)
|
|
eieioSTP
|
|
tst.b vBufB(A1) ; (each of these should be ~1.2µs)
|
|
eieioSTP
|
|
tst.b vBufB(A1)
|
|
eieioSTP
|
|
tst.b vBufB(A1)
|
|
eieioSTP
|
|
tst.b vBufB(A1)
|
|
eieioSTP
|
|
tst.b vBufB(A1)
|
|
eieioSTP
|
|
tst.b vBufB(A1) ; <H4>
|
|
eieioSTP
|
|
BCLR #4,vACR(A1) ; change to shift-in mode
|
|
eieioSTP
|
|
TST.B vSR(A1) ; empty shift reg to start shifting
|
|
eieioSTP
|
|
EOR.B D1,vBufB(A1) ; change the state
|
|
eieioSTP
|
|
MOVE.L (SP)+,ShiftIntResume(A3); save resume address
|
|
RTS ; return to callers caller, wait for interrupt
|
|
|
|
|
|
@getNextByte
|
|
LEA fDBCnt(A3),A0 ; point to the length byte of the buffer
|
|
MOVEQ #1,D0 ; zero extend the index
|
|
ADD.B (A0),D0 ; get, and increment the index
|
|
MOVE.B D0,(A0) ; update the index
|
|
eieioSTP
|
|
MOVE.B vSR(a1),(A0,D0.W) ; save the new byte in the buffer
|
|
eieioSTP
|
|
EORI.B #(1<<vFDesk1)|\
|
|
(1<<vFDesk2),vBufB(A1) ; alternate between state 1 and state 2
|
|
eieioSTP
|
|
MOVE.L (SP)+,ShiftIntResume(A3); save resume address
|
|
eieioSTP
|
|
RTS ; return to callers caller, wait for interrupt
|
|
|
|
; send an explicit Listen command, send data buffer.
|
|
;
|
|
; Inputs: D2 - length of transmit buffer data
|
|
; D3 - command byte / implicit flag (bit 31)
|
|
; A2 - pointer to buffer containing transmit data
|
|
; A3 - pointer to ADBBase
|
|
|
|
@listen SUBQ.B #2,D2 ; check for min length of 2
|
|
BHS.S @minOK ; if >= 2, use it
|
|
MOVEQ #0,D2 ; otherwise use 0, which will become 2
|
|
@minOK SUBQ.B #8-2,D2 ; check for max length of 8
|
|
BLS.S @maxOK ; if <= 8, use it
|
|
MOVEQ #0,D2 ; otherwise use 0, which will become 8
|
|
@maxOK ADDQ.B #8,D2 ; restore count
|
|
MOVE.B D2,fDBCnt(A3) ; update buffer length
|
|
MOVE.L A2,ListenBuffPtr(A3); save buffer starting address
|
|
|
|
BSR.S @sendCmd ; send out the command byte
|
|
BEQ @autoReply ; see if auto poll data returned instead
|
|
|
|
BSR.S @sendFirstByte ; send the first byte
|
|
BNE.S @noListenTimeout ; see if timeout occured
|
|
BSET #fDBNoReply,FDBAuFlag(A3) ; indicate that no reply data was returned
|
|
@noListenTimeout
|
|
BSR.S @sendNextByte ; send the second byte
|
|
BNE.S @sendLoop ; if no SRQ, send the data
|
|
BSET #fDBSRQ,FDBAuFlag(A3) ; remember that a service request was returned
|
|
|
|
@sendLoop TST.B fDBCnt(A3) ; see if end of buffer reached
|
|
BEQ.S VIAReqDone ; leave when count is zero, no reply data
|
|
BSR.S @sendNextByte ; send another byte
|
|
BRA.S @sendLoop ; loop until count exhausted
|
|
|
|
|
|
|
|
@sendFirstByte
|
|
MOVEQ #(1<<vFDesk1),D1 ; change from state 0 to state 1
|
|
BRA.S @sendByte ; join common code
|
|
|
|
@sendNextByte
|
|
MOVEQ #(1<<vFDesk1)|\
|
|
(1<<vFDesk2),D1 ; alternate between state 1 and state 2
|
|
@sendByte MOVEA.L ListenBuffPtr(A3),A0; get the buffer pointer
|
|
eieioSTP
|
|
MOVE.B (A0)+,vSR(A1) ; send the byte
|
|
eieioSTP
|
|
MOVE.L A0,ListenBuffPtr(A3); update the buffer pointer
|
|
SUBQ.B #1,fDBCnt(A3) ; decrement the send count
|
|
eieioSTP
|
|
EOR.B D1,vBufB(A1) ; change the state
|
|
eieioSTP
|
|
MOVE.L (SP)+,ShiftIntResume(A3); save resume address
|
|
eieioSTP
|
|
RTS ; return to callers caller, wait for interrupt
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: FDBShiftInt
|
|
;
|
|
; Inputs: A1 - pointer to base of VIA1
|
|
;
|
|
; Outputs: A1 - pointer to base of VIA1
|
|
; A3 - pointer to ADBBase
|
|
; CCR - BEQ/BNE based on state of vFDBInt bit in VIA1's buffer B
|
|
;
|
|
; Trashes: A0
|
|
;
|
|
; Function: handles the shift register interrupt and resumes asynchronous processing
|
|
;________________________________________________________________________________________
|
|
|
|
FDBShiftInt MOVEA.L ADBBase,A3 ; point to ADB globals
|
|
MOVEA.L ShiftIntResume(A3),A0 ; and get the address to resume at
|
|
eieioSTP
|
|
BTST #vFDBInt,vBufB(A1) ; test the FDBInt~ status
|
|
eieioSTP
|
|
JMP (A0) ; resume async processing
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: VIAReqDone
|
|
;
|
|
; Inputs: A3 - pointer to ADBBase
|
|
;
|
|
; Outputs: A2 - pointer to receive data buffer
|
|
; A3 - pointer to ADBBase
|
|
; D2 - number of bytes of receive data
|
|
; D3 - command byte (bits 0-7) + SRQ flag (bit 31)
|
|
;
|
|
; Trashes: A0,D0,D1
|
|
;
|
|
; Function: completion routine for servicing replies from the ADB transceiver
|
|
;________________________________________________________________________________________
|
|
|
|
VIAReqDone MOVE.B FDBAuFlag(A3),D0 ; get the flags
|
|
MOVE.B fDBCmd(A3),D1 ; and the command
|
|
MOVEQ #(1<<fDBSRQ),D3 ; mask to test for SRQ pending
|
|
AND.B D0,D3
|
|
NEG.L D3 ; set bit 31 if SRQ pending
|
|
MOVE.B D1,D3 ; insert the command byte
|
|
|
|
LSR.B #4,D1 ; isolate the device address
|
|
TST.L D3 ; was there an SRQ?
|
|
BPL.S @NoSRQ ; -> no, don't advance the poll address
|
|
|
|
MOVE.W DevMap(A3),D2 ; get the list of possible address to search
|
|
BSET D1,D2 ; if no other bits are set, come back to this one
|
|
|
|
@SRQloop ADDQ.B #1,D1 ; try the next address
|
|
ANDI.B #$0F,D1 ; wrapping around if needed (clear bit 7, autopoll addr change)
|
|
BTST D1,D2 ; is there a device with that address?
|
|
BEQ.S @SRQloop ; -> no, try the next address
|
|
|
|
@NoSRQ MOVE.B D1,PollAddr(A3) ; remember where to auto/SRQ poll next
|
|
|
|
LEA fDBCnt(A3),A0 ; point to the length byte of the buffer
|
|
MOVEQ #0,D2 ; zero extend the length
|
|
MOVE.B (A0)+,D2 ; get length of receive data
|
|
MOVEA.L A0,A2 ; point to the data buffer
|
|
|
|
CLR.B FDBAuFlag(A3) ; clear the flags, especially fDBBusy
|
|
BTST #fDBAPoll,D0 ; see what kind of request completed
|
|
BNE.L ImplicitRequestDone ; auto poll data returned, call handler
|
|
BRA.L ExplicitRequestDone ; if explicit, call the completion routine
|
|
|
|
|
|
ENDIF ; {ViaADB}
|
|
|
|
|
|
IF ViaADB | hasEgret THEN
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: VIADebugPoll,EgretDebugPoll
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: A0,A1,A3,...
|
|
;
|
|
; Function: DebugUtil code to check if ADB data is available, for implementations that
|
|
; use the VIA1 shift register interrupt
|
|
;________________________________________________________________________________________
|
|
|
|
VIADebugPoll
|
|
JSR ([jCacheFlush]) ; Temporary “fix” so that MacsBug works on Q700s. <SM4>
|
|
EgretDebugPoll
|
|
MOVEA.L VIA,A1 ; point to the VIA
|
|
eieioSTP
|
|
BTST #ifSR,vIFR(A1) ; is the shift register full?
|
|
eieioSTP
|
|
BEQ.S @PollDone ; -> no, just return
|
|
MOVE.L Lvl1DT+(4*ifSR),-(SP) ; get the handler address
|
|
@PollDone RTS ; and call the interrupt handler
|
|
|
|
ENDIF
|
|
|
|
|
|
IF PwrMgrADB THEN
|
|
;•••••••••••••••••••••••••••••••••••• Power Manager •••••••••••••••••••••••••••••••••••••
|
|
|
|
WITH pmCommandRec
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: PMgrInitADB
|
|
;
|
|
; Inputs: A3 - pointer to ADBBase
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: A0
|
|
;
|
|
; Function: initializes the ADB Manager for Power Manager based ADB
|
|
;________________________________________________________________________________________
|
|
|
|
PMgrInitADB LEA PMgrStartReq,A0 ; setup the procedure to start an ADB request
|
|
MOVE.L A0,StartReqProc(A3)
|
|
LEA PMgrReqDone,A0 ; get the address of the interrupt handler
|
|
MOVE.L A0,Lvl1DT+(4*ifSR) ; and install it as the SR interrupt receiver
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: PMgrEnableKbdNMI
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: none
|
|
;
|
|
; Function: Enables the NMI "programmer's key" on Power Manager based systems so we can
|
|
; break into a debugger if one is installed. The reason this is an option is
|
|
; that if the key is turned on without a debugger, the unaware user can die a
|
|
; gory "deep shit" death if they hit the key accidentally.
|
|
;________________________________________________________________________________________
|
|
|
|
PMgrEnableKbdNMI
|
|
MOVEM.L D0/A0,-(SP)
|
|
MOVE.B #1,-(SP) ; buffer contains enable flag
|
|
MOVE.L SP,-(SP) ; pmRBuffer
|
|
MOVE.L (SP),-(SP) ; pmSBuffer
|
|
MOVE.W #1,-(SP) ; pmLength
|
|
MOVE.W #$24,-(SP) ; pmCommand = enable/disable keyboard NMI
|
|
MOVEA.L SP,A0 ; point to the parameter block
|
|
_PMgrOp ; send the command
|
|
LEA pmRBuffer+4+2(SP),SP ; clean up the stack
|
|
MOVEM.L (SP)+,D0/A0
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: PMgrStartReq
|
|
;
|
|
; Inputs: A2 - pointer to transmit data buffer
|
|
; A3 - pointer to ADBBase
|
|
; D2 - number of bytes of transmit data
|
|
; D3 - command byte (bits 0-7) + implicit flag (bit 31)
|
|
;
|
|
; Outputs: A1 - pointer to base of VIA1
|
|
; A3 - pointer to ADBBase
|
|
;
|
|
; Trashes: A0,D0,D3
|
|
;
|
|
; Function: sends an ADB request to the Power Manager and asynchronously waits for a reply
|
|
;________________________________________________________________________________________
|
|
|
|
PMgrStartReq
|
|
MOVEA.L VIA,A1 ; point to the base of VIA1
|
|
eieioSTP
|
|
MOVE.B #(0<<ifIRQ)|\
|
|
(1<<ifCB1),vIER(A1) ; and disable the interrupt since it's set
|
|
|
|
eieioSTP
|
|
LEA -12(SP),SP ; allocate a buffer on the stack
|
|
MOVEA.L SP,A0 ; and point to it
|
|
MOVE.L A0,-(SP) ; pmRBuffer
|
|
MOVE.L A0,-(SP) ; pmSBuffer
|
|
MOVEQ #3,D0 ; transmit length is size of buffer + 3
|
|
ADD.B D2,D0
|
|
MOVE.W D0,-(SP) ; pmLength
|
|
MOVE.W #PMgrADB,-(SP) ; pmCommand
|
|
|
|
MOVEQ #(0<<pMgrAutoPoll)|\
|
|
(0<<pMgrPollEnable),D0 ; explicit, poll disabled
|
|
TST.L D3 ; is this an explicit request?
|
|
BMI.S @Implicit ; -> no, go set exerything up
|
|
|
|
BSET #fDBExpActive,fDBAuFlag(A3) ; remember that an explicit command has been sent
|
|
BNE.S @DontCall ; -> it's already been sent, so just exit
|
|
BRA.S @Explicit
|
|
|
|
@Implicit MOVE.B PollAddr(a3),d3 ; get the auto/srq polling address
|
|
BMI.S @DontCall ; -> already autopolling, so don't call to restart
|
|
TestFor PMgrNewIntf ; does the PMGR do auto-polling?
|
|
BEQ.S @oldPMGR ; -> no, let the CPU manage it
|
|
MOVE.B #(1<<pMgrSetPoll)|\
|
|
(1<<pMgrAutoPoll)|\
|
|
(1<<pMgrPollEnable),D0 ; set autopoll, poll enabled if implicit
|
|
SWAP D0
|
|
MOVE.W DevMap(A3),D0 ; pass the Polling Enable bit map
|
|
MOVE.L D0,(A0) ; fill in our transmit buffer
|
|
MOVE.W #4,pmLength(SP) ; reset count to 4 bytes for this command
|
|
BRA.S @SendCmd ; and send it
|
|
|
|
@oldPMGR MOVEQ #1<<pMgrAutoPoll,D0 ; set auto poll if implicit
|
|
LSL.B #4,D3 ; position the address
|
|
ORI.B #talkCmd+0,D3 ; make it a Talk R0 command
|
|
|
|
@Explicit MOVE.B D3,(A0)+ ; command
|
|
MOVE.B D0,(A0)+ ; flags
|
|
MOVE.B D2,(A0)+ ; send data count
|
|
BRA.S @CopyStart ; start the copy
|
|
|
|
@CopyLoop MOVE.B (A2)+,(A0)+ ; copy into the message buffer one byte at a time
|
|
@CopyStart DBRA D2,@CopyLoop
|
|
|
|
@SendCmd MOVEA.L SP,A0 ; point to the parameter block
|
|
_PmgrOp ; send the request to the PMGR
|
|
@DontCall LEA pmRBuffer+4+12(SP),SP ; clean up the stack
|
|
|
|
eieioSTP
|
|
MOVE.B #(1<<ifIRQ)|\
|
|
(1<<ifCB1),vIER(A1) ; re-enable PMGR interrupts
|
|
eieioSTP
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: PMgrReqDone
|
|
;
|
|
; Inputs: A0 - ???????????????????????????????
|
|
; A3 - pointer to ADBBase
|
|
;
|
|
; Outputs: A2 - pointer to receive data buffer
|
|
; A3 - pointer to ADBBase
|
|
; D2 - number of bytes of receive data
|
|
; D3 - command byte (bits 0-7) + SRQ flag (bit 31)
|
|
;
|
|
; Trashes: A0,D0,D1
|
|
;
|
|
; Function: completion routine for servicing messages received from the PMGR
|
|
;________________________________________________________________________________________
|
|
|
|
PMgrReqDone MOVEA.L ADBBase,A3 ; point to ADB globals
|
|
|
|
MOVE.B (A0)+,D1 ; get the command that completed
|
|
MOVE.B (A0)+,D0 ; and the flags byte
|
|
|
|
MOVEQ #(1<<pMgrSRQ),D3 ; mask to test for SRQ pending
|
|
AND.B D0,D3
|
|
NEG.L D3 ; set bit 31 if SRQ pending
|
|
MOVE.B D1,D3 ; insert the command byte
|
|
|
|
; Keep the ADB Parser program happy by updating the following variables.
|
|
; They are not used by this implementation, but we fill them in with
|
|
; approximate values to make the tool happy.
|
|
|
|
MOVE.B D3,fDBCmd(A3) ; save the last ADB command
|
|
MOVE.B D3,pollCmd(A3) ; assume that it was a poll command
|
|
|
|
LSR.B #4,D1 ; isolate the device address
|
|
BSET #7,D1 ; indicate no change in autopoll address needed
|
|
|
|
TestFor PMgrNewIntf ; does the PMGR do auto-polling?
|
|
BEQ.S @oldPMGR ; -> no, let the CPU manage it
|
|
BTST #pMgrPollEnable,D0 ; is polling enabled?
|
|
BNE.S @noSRQ ; -> yes, skip
|
|
BCLR #7,D1 ; indicate a new autopoll address is needed
|
|
BRA.S @noSRQ
|
|
|
|
@oldPMGR TST.L D3 ; was there an SRQ?
|
|
BPL.S @noSRQ ; -> no, don't advance the poll address
|
|
|
|
MOVE.W DevMap(A3),D2 ; get the list of possible address to search
|
|
BSET D1,D2 ; if no other bits are set, come back to this one
|
|
|
|
@SRQloop ADDQ.B #1,D1 ; try the next address
|
|
ANDI.B #$0F,D1 ; wrapping around if needed (clear bit 7, autopoll addr change)
|
|
BTST D1,D2 ; is there a device with that address?
|
|
BEQ.S @SRQloop ; -> no, try the next address
|
|
|
|
@noSRQ MOVE.B D1,PollAddr(A3) ; remember where to auto/SRQ poll next
|
|
|
|
MOVEQ #0,D2 ; get the length of received data
|
|
MOVE.B (A0)+,D2
|
|
MOVEA.L A0,A2 ; point to the data buffer
|
|
|
|
BTST #pMgrAutoPoll,D0 ; see what kind of request completed
|
|
BNE.S @Implicit ; -> polling command, so figure out what to do
|
|
|
|
TestFor PMgrNewIntf ; does the PMGR do auto-polling?
|
|
BNE.S @Explicit ; -> yes
|
|
BCLR #7,PollAddr(A3) ; indicate that PollAddr address should be used
|
|
@Explicit BCLR #fDBExpActive,fDBAuFlag(A3) ; remember that it has completed
|
|
BRA.L ExplicitRequestDone ; call the completion routine
|
|
|
|
@Implicit BRA.L ImplicitRequestDone ; auto poll data was returned, so call the handler
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: PMgrDebugPoll
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: A1
|
|
;
|
|
; Function: DebugUtil code to check if ADB data is available
|
|
;________________________________________________________________________________________
|
|
|
|
PMgrDebugPoll
|
|
MOVEA.L VIA,A1 ; point to the VIA
|
|
eieioSTP
|
|
BTST #ifCB1,vIFR(A1) ; does the PMgr have some data?
|
|
eieioSTP
|
|
BEQ.S @PollDone ; -> no, just return
|
|
MOVE.L Lvl1DT+(4*ifCB1),-(SP) ; get the handler address
|
|
@PollDone RTS ; and call the interrupt handler
|
|
|
|
|
|
ENDIF ; {PwrMgrADB}
|
|
|
|
|
|
|
|
IF hasEgret THEN
|
|
;•••••••••••••••••••••••••••••••••••••••• Egret •••••••••••••••••••••••••••••••••••••••••
|
|
|
|
WITH EgretPB
|
|
|
|
jEgretDispatch EQU OSTable+($92*4) ; OS trap table entry for _EgretDispatch
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: EgretInitADB
|
|
;
|
|
; Inputs: A3 - pointer to ADBBase
|
|
;
|
|
; Outputs:
|
|
;
|
|
; Trashes: A0,A1
|
|
;
|
|
; Function: initializes the ADB Manager for Power Manager based ADB
|
|
;________________________________________________________________________________________
|
|
|
|
EgretInitADB
|
|
LEA EgretStartReq,A0 ; setup the procedure to start an ADB request
|
|
MOVE.L A0,StartReqProc(A3)
|
|
MOVE.W #(specialPkt<<8)+\ ; pbCmdType = special packet
|
|
(aPoll<<0),\ ; pbCmd = install/remove autopoll handler
|
|
ImplicitEPB.pbCmdType(A3) ; init the param block
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: EgretStartReq
|
|
;
|
|
; Inputs: A2 - pointer to transmit data buffer
|
|
; A3 - pointer to ADBBase
|
|
; D2 - number of bytes of transmit data
|
|
; D3 - command byte (bits 0-7) + implicit flag (bit 31)
|
|
;
|
|
; Outputs: A1 - pointer to base of VIA1
|
|
; A3 - pointer to ADBBase
|
|
;
|
|
; Trashes: A0,A1,A2,D0,D1,D2,D3
|
|
;
|
|
; Function: sends an ADB request to Egret and asynchronously waits for a reply
|
|
;________________________________________________________________________________________
|
|
|
|
EgretStartReq
|
|
TST.L D3 ; is this an implicit request?
|
|
BPL.S @Explicit ; -> no
|
|
|
|
@Implicit BTST #fDBInit,fDBFlag(A3) ; is initialization happening?
|
|
BNE.S @impDone ; -> yes, implicit commands are ignored
|
|
BSET #fDBImpInited,fDBAuFlag(A3) ; has implicit command initialization occured?
|
|
BNE.S @impDone ; -> yes, we're done
|
|
|
|
LEA ImplicitEPB(A3),A0 ; point to the autopoll parameter block
|
|
LEA @ImplicitCompleted,A1 ; handler address
|
|
MOVE.L A1,pbCompletion(A0) ; install the handler
|
|
BSR @SendToEgret ; install the autopoll handler
|
|
|
|
MOVE.L #(pseudoPkt<<24)\ ; pcCmdType = pseudo packet
|
|
+(wrDevList<<16),D0 ; pbCmd = write device list
|
|
MOVE.W DevMap(A3),D0 ; pbParam = device map
|
|
BSR.S @syncReq ; send command to specify auto polling addresses
|
|
|
|
MOVE.L #(pseudoPkt<<24)\ ; pcCmdType = pseudo packet
|
|
+(aPoll<<16)\ ; pbCmd = autoPoll
|
|
+($FF<<8),D0 ; pbParam = $FF (only high byte is used)
|
|
; send command to start auto polling
|
|
|
|
@syncReq LEA -EgretPBSize(SP),SP ; put a parameter block on the stack
|
|
MOVEA.L SP,A0 ; and point to it
|
|
MOVE.L D0,pbCmdType(A0) ; init pcCmdType, pbCmd, and high word of pbParam
|
|
CLR.L pbCompletion(A0) ; no completion routine, sync call
|
|
BSR.S @SendToEgret ; send the request off to the ADB micro
|
|
LEA EgretPBSize(SP),SP ; deallocate the param block
|
|
@ignoreExplicit
|
|
@impDone RTS ; auto-polling/srq data will arrive unsolicited from now on
|
|
|
|
|
|
@ImplicitCompleted
|
|
MOVEQ #(1<<EgSRQ),D3 ; mask to test for SRQ pending
|
|
eieioSTP
|
|
AND.B (A1)+,D3
|
|
eieioSTP
|
|
NEG.L D3 ; set bit 31 if SRQ pending
|
|
eieioSTP
|
|
MOVE.B (A1)+,D3 ; get the ADB command byte
|
|
MOVEQ #0,D2 ; zero extend the length
|
|
eieioSTP
|
|
MOVE.W D0,D2
|
|
MOVEA.L A1,A2 ; get the buffer pointer
|
|
BSR @FillInVars ; setup A3 and ADB globals for ADB Parser
|
|
BRA.L ImplicitRequestDone ; return control to the ADB Manager
|
|
|
|
|
|
@Explicit BSET #fDBExpRunning,fDBAuFlag(A3); explicit command starting, so exclude new ones
|
|
BNE.S @IgnoreExplicit ; -> it's already in progress, so don't run it twice
|
|
MOVE.B D3,ExplicitEPB.pbCmd(A3) ; setup the ADB command,
|
|
MOVE.W D2,ExplicitEPB.pbByteCnt(A3); byte count,
|
|
MOVE.L A2,ExplicitEPB.pbBufPtr(A3) ; buffer pointer
|
|
|
|
BSET #fDBExpInited,fDBAuFlag(A3) ; see if explicit command initialization has occured
|
|
BNE.S @expInited ; if already inited, no need to change anything
|
|
|
|
LEA @ExplicitCompleted,A0 ; explicit request completion routine address
|
|
MOVE.L A0,ExplicitEPB.pbCompletion(A3) ; setup buffer pointer
|
|
|
|
LEA ImplicitEPB(A3),A0 ; point to the autopoll parameter block
|
|
CLR.L pbCompletion(A0) ; no completion routine
|
|
BSR.S @SendToEgret ; remove the auto poll handler
|
|
|
|
MOVE.L #(pseudoPkt<<24)\ ; pcCmdType = pseudo packet
|
|
+(aPoll<<16)\ ; pbCmd = autoPoll
|
|
+($00<<8),D0 ; pbParam = $00 (only high byte is used)
|
|
BSR.S @syncReq ; send command to stop auto polling
|
|
|
|
@expInited LEA ExplicitEPB(A3),A0 ; point to the param block
|
|
@SendToEgret
|
|
MOVEQ #0,D1 ; zero the trapword flag bits (in case they ever get used)
|
|
MOVEA.L jEgretDispatch,A2 ; get the OSTrap table entry
|
|
JMP (A2) ; _EgretDispatch, issue the request (asynchronously), return
|
|
|
|
|
|
@ExplicitCompleted ; A0 points to the EgretPB
|
|
MOVEQ #(1<<EgSRQ),D3 ; mask to test for SRQ pending
|
|
AND.B pbFlags(A0),D3
|
|
NEG.L D3 ; set bit 31 if SRQ pending
|
|
MOVE.B pbCmd(A0),D3 ; get the ADB command byte
|
|
MOVEQ #0,D2 ; zero extend the length
|
|
MOVE.W pbByteCnt(A0),D2
|
|
MOVEA.L pbBufPtr(A0),A2 ; get the buffer pointer
|
|
BSR.S @FillInVars ; setup A3 and ADB globals for ADB Parser
|
|
BCLR #fDBExpRunning,fDBAuFlag(A3) ; explicit command completed, allow new ones
|
|
|
|
; Egret must check the ADB Device address against the Device Bitmap to see if the device exists.
|
|
; If it does not, force Egret to poll the mouse as the MRU device and keyboard as the LRU device.
|
|
; This fixes an Egret bug.
|
|
|
|
MOVE.W Devmap(A3),D1 ; get the ADB device Bitmap
|
|
btst.l D0,D1 ; does this device exist?
|
|
BNE.S @ExpDone ; -> yes, done
|
|
|
|
LEA -EgretPBSize(SP),SP ; put a parameter block on the stack
|
|
MOVEA.L SP,A0 ; and point to it
|
|
CLR.L pbCompletion(A0) ; no completion routine
|
|
MOVE.W #(pseudoPkt<<8)+\
|
|
(Wr6805addr<<0),pbCmdType(A0) ; packet type & command
|
|
MOVE.W #(MouseAddr<<12)+\ ; put mouse address into bits 12-15 (MRU)
|
|
(KbdAddr<<4),-(SP) ; and keyboard address into bits 4-7 (LRU)
|
|
MOVE.L SP,pbBufPtr(A0) ; buffer pointer
|
|
MOVE.W #MRUAddr,pbParam(A0) ; Egret address to write
|
|
MOVE.W #2,pbByteCnt(A0) ; 2 bytes to write
|
|
_EgretDispatch ; issue the call
|
|
LEA EgretPbSize+2(SP),SP ; clean up the stack
|
|
|
|
@ExpDone BRA.L ExplicitRequestDone ; return control to the ADB Manager
|
|
|
|
|
|
; Keep the ADB Parser program happy by updating the following variables.
|
|
; They are not used by this implementation, but we fill them in with
|
|
; approximate values to make the tool happy.
|
|
|
|
@FillInVars MOVEA.L ADBBase,A3 ; point to ADB globals in low memory
|
|
MOVE.B D3,fDBCmd(A3) ; last ADB command
|
|
MOVE.B D3,pollCmd(A3) ; assume that it was a poll command
|
|
MOVE.B D3,D0 ; copy the command
|
|
LSR.B #4,D0 ; get the address
|
|
MOVE.B D0,pollAddr(A3) ; assume that it was a poll address
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: CudaDebugEnter
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: D0, D1, A0
|
|
;
|
|
; Function: DebugUtil code to be executed when entering a debugger: turns off one-second
|
|
; interrupts
|
|
;________________________________________________________________________________________
|
|
|
|
CudaDebugEnter
|
|
; fall thru into EgretDebugEnter
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: EgretDebugEnter
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: D0, D1, A0
|
|
;
|
|
; Function: DebugUtil code to be executed when entering a debugger: turns off one-second
|
|
; interrupts
|
|
;________________________________________________________________________________________
|
|
|
|
EgretDebugEnter
|
|
MOVEQ #0,D1 ; turn off mode 3 clock data packets
|
|
BRA.S EgretDebugCommon
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: CudaDebugExit
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: D0, D1, A0
|
|
;
|
|
; Function: DebugUtil code to be executed when exiting a debugger: turns on one-second
|
|
; interrupts
|
|
;________________________________________________________________________________________
|
|
|
|
CudaDebugExit
|
|
MOVEQ #PDMDebugCont,D1 ; continue PDM <LW2>
|
|
BSR.S EgretDebugPDM ; <P3>
|
|
; fall thru into EgretDebugExit
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: EgretDebugExit
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: D0, D1, A0
|
|
;
|
|
; Function: DebugUtil code to be executed when exiting a debugger: turns on one-second
|
|
; interrupts
|
|
;________________________________________________________________________________________
|
|
|
|
EgretDebugExit
|
|
MOVEQ #Mode3Clock,D1 ; turn on mode 3 clock data packets
|
|
EgretDebugCommon
|
|
MOVEQ #EgretPBSize/2-1,D0
|
|
@ClearPB CLR.W -(SP) ; zero all fields in the parameter block
|
|
DBRA D0,@ClearPB ; (forces mode 0 and no completion vector)
|
|
MOVEA.L SP,A0 ; point to the parameter block
|
|
MOVE.W #(pseudoPkt<<8)+\
|
|
(Wr1SecMode<<0),pbCmdType(A0) ; set up the packet type and command
|
|
MOVE.B D1,pbParam(A0) ; turn on/off Mode 3 clock data packets
|
|
_EgretDispatch ; turn on/off one-second interrupts
|
|
LEA EgretPbSize(SP),SP ; clean up the stack
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: EgretDebugPDM
|
|
;
|
|
; Inputs: D1 - contains the PDM Selector
|
|
; Disable = 0, Enable = 1, Suspend = 2, Continue = 3
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: D0, D1, A0
|
|
;
|
|
; Function: DebugUtil code to be executed when entering/exiting a debugger:
|
|
; if Egret chip with Cuda firmware, suspend/continue PDM
|
|
;________________________________________________________________________________________
|
|
|
|
EgretDebugPDM
|
|
moveq #EgretPBSize/2-1,d0 ; <P3>
|
|
@ClearPB clr.w -(sp) ; zero all fields in the parameter block <P3>
|
|
dbra d0,@ClearPB ; (forces mode 0 and no completion vector) <P3>
|
|
movea.l sp,a0 ; point to the parameter block <P3>
|
|
move.w #(PseudoPkt << 8) \
|
|
+ EnDisPDM,pbCmdType(a0); Enable PowerDown Messages <P3>
|
|
move.b d1,pbParam(a0) ; PDM Selector <P3>
|
|
_EgretDispatch ; <P3>
|
|
LEA EgretPbSize(SP),SP ; clean up the stack <P3>
|
|
rts
|
|
|
|
|
|
ENDIF ; {hasEgret}
|
|
|
|
|
|
|
|
IF IopADB THEN
|
|
;••••••••••••••••••••••••••••••••••••••••• IOP ••••••••••••••••••••••••••••••••••••••••••
|
|
|
|
WITH IOPRequestInfo
|
|
|
|
IMPORT IOPInterrupt
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: IOPInitADB
|
|
;
|
|
; Inputs: A3 - pointer to ADBBase
|
|
;
|
|
; Outputs:
|
|
;
|
|
; Trashes: A0,A1
|
|
;
|
|
; Function: initializes the ADB Manager for IOP based ADB
|
|
;________________________________________________________________________________________
|
|
|
|
IOPInitADB LEA IOPStartReq,A0 ; setup the procedure to start an ADB request
|
|
MOVE.L A0,StartReqProc(A3)
|
|
|
|
; initialize the XmtRequest message (all other fields remain zero)
|
|
eieioSTP
|
|
MOVE.B #ADBIopNum,XmtRequest.irIOPNumber(A3)
|
|
eieioSTP
|
|
MOVE.B #IOPRequestInfo.irSendXmtMessage,XmtRequest.irRequestKind(A3)
|
|
eieioSTP
|
|
MOVE.B #ADBMsgNum,XmtRequest.irMsgNumber(A3)
|
|
eieioSTP
|
|
LEA XmtMsg(A3),A0 ; get pointer to message buffer
|
|
eieioSTP
|
|
MOVE.L A0,XmtRequest.irMessagePtr(A3)
|
|
eieioSTP
|
|
|
|
; initialize the RcvRequest message (all other fields remain zero)
|
|
|
|
eieioSTP
|
|
MOVE.B #ADBIopNum,RcvRequest.irIOPNumber(A3)
|
|
eieioSTP
|
|
MOVE.B #IOPRequestInfo.irWaitRcvMessage,RcvRequest.irRequestKind(A3)
|
|
eieioSTP
|
|
MOVE.B #ADBMsgNum,RcvRequest.irMsgNumber(A3)
|
|
eieioSTP
|
|
MOVE.B #ADBMsg.ADBMsgSize,RcvRequest.irMessageLen(A3)
|
|
eieioSTP
|
|
LEA RcvMsg(A3),A0 ; get pointer to message buffer
|
|
eieioSTP
|
|
MOVE.L A0,RcvRequest.irMessagePtr(A3)
|
|
eieioSTP
|
|
MOVE.L A0,RcvRequest.irReplyPtr(A3)
|
|
eieioSTP
|
|
LEA IOPReqDone,A0 ; get handler pointer
|
|
eieioSTP
|
|
MOVE.L A0,RcvRequest.irHandler(A3)
|
|
eieioSTP
|
|
LEA RcvRequest(A3),A0 ; setup pointer to param block
|
|
eieioSTP
|
|
_IOPMsgRequest ; install the Rcv message handler
|
|
eieioSTP
|
|
MOVE.B #IOPRequestInfo.irSendRcvReply,RcvRequest.irRequestKind(A3)
|
|
eieioSTP
|
|
RTS
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: IOPStartReq
|
|
;
|
|
; Inputs: A2 - pointer to transmit data buffer
|
|
; A3 - pointer to ADBBase
|
|
; D2 - number of bytes of transmit data
|
|
; D3 - command byte (bits 0-7) + implicit flag (bit 31)
|
|
;
|
|
; Outputs: A3 - pointer to ADBBase
|
|
;
|
|
; Trashes: A0,A1,A2,D0,D1,D2
|
|
;
|
|
; Function: sends an ADB request to the IOP and asynchronously waits for a reply
|
|
;________________________________________________________________________________________
|
|
|
|
IOPStartReq MOVEQ #ADBMsg.ADBData-ADBMsg+2,D0 ; length of msg preceeding data +2 for implicit
|
|
ADD.B D2,D0 ; d0 := length of message buffer
|
|
eieioSTP
|
|
BCLR #fDBUseRcvMsg,fDBAuFlag(A3) ; see which buffer/message to use
|
|
eieioSTP
|
|
BNE.S @useRcv ; if rcv available, use it
|
|
|
|
@useXmt LEA XmtRequest(A3),A0 ; get the iop xmt request param block
|
|
LEA XmtMsg(A3),A1 ; use the xmt message buffer
|
|
eieioSTP
|
|
MOVE.B D0,irMessageLen(A0) ; setup the message length
|
|
eieioSTP
|
|
BRA.S @fillInReq ; fill in the remaining fields and exit
|
|
|
|
@useRcv LEA RcvRequest(A3),A0 ; get the iop rcv request param block
|
|
LEA RcvMsg(A3),A1 ; use the rcv message buffer
|
|
eieioSTP
|
|
MOVE.B D0,irReplyLen(A0) ; setup the reply length
|
|
eieioSTP
|
|
|
|
@fillInReq
|
|
eieioSTP
|
|
MOVE.W #(((1<<PollEnable)\ ; setup ADBMsg.Flags, enable polling, assume implicit
|
|
+(1<<SetPollEnables))<<8)\ ; indicate that DevMap is being passed
|
|
+2,Flags(A1) ; setup ADBMsg.DataCount = 2 (DevMap is 2 bytes long)
|
|
eieioSTP
|
|
TST.L D3 ; see if implicit
|
|
eieioSTP
|
|
BMI.S @implicit ; if implicit, ADBCmd is ignored, send DevMap
|
|
|
|
eieioSTP
|
|
CLR.W Flags(A1) ; setup ADBMsg.Flags, implicit, idle, DataCount
|
|
eieioSTP
|
|
BSET #fDBExpActive,fDBAuFlag(A3) ; remember that an explicit command has been sent
|
|
eieioSTP
|
|
BNE.S @SendToIOP ; if it had already been sent, just go idle
|
|
|
|
eieioSTP
|
|
MOVE.B #(1<<ExplicitCmd),(A1)+ ; setup ADBMsg.Flags, explicit command
|
|
eieioSTP
|
|
MOVE.B D2,(A1)+ ; setup ADBMsg.DataCount
|
|
eieioSTP
|
|
MOVE.B D3,(A1)+ ; setup ADBMsg.ADBCmd
|
|
eieioSTP
|
|
BRA.S @copyStart ; start the copy
|
|
eieioSTP
|
|
@copyLoop
|
|
eieioSTP
|
|
MOVE.B (A2)+,(A1)+ ; copy into the message buffer one byte at a time
|
|
eieioSTP
|
|
@copyStart
|
|
eieioSTP
|
|
DBRA D2,@copyLoop ; loop for all bytes
|
|
eieioSTP
|
|
|
|
@SendToIOP MOVEA.L jIOPMsgRequest,A2 ; get the OSTrap table entry
|
|
JMP (A2) ; _IOPMsgRequest send the message (Asynchronously), return
|
|
|
|
@implicit
|
|
eieioSTP
|
|
MOVE.W DevMap(A3),ADBData(A1) ; pass the Polling Enable bit map
|
|
eieioSTP
|
|
BRA.S @SendToIOP ; pass it to the IOP
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: IOPReqDone
|
|
;
|
|
; Inputs: A2 - pointer to receive data buffer
|
|
; A3 - pointer to ADBBase
|
|
; D2 - number of bytes of receive data
|
|
; D3 - command byte (bits 0-7) + SRQ flag (bit 31)
|
|
;
|
|
; Outputs: A3 - pointer to ADBBase
|
|
;
|
|
; Trashes: A0,A1,A2,A3,D0,D1,D2,D3
|
|
;
|
|
; Function: completion routine for servicing messages received from the IOP
|
|
;________________________________________________________________________________________
|
|
|
|
IOPReqDone MOVEA.L ADBBase,A3 ; point to ADB globals in low memory
|
|
eieioSTP
|
|
MOVE.B RcvMsg.Flags(A3),D0 ; get flags telling what interrupt occurred
|
|
MOVEQ #(1<<SRQReq),D3 ; mask to test for SRQ pending
|
|
AND.B D0,D3 ; isolate the bit
|
|
NEG.L D3 ; set bit 31 if SRQ pending
|
|
eieioSTP
|
|
MOVE.B RcvMsg.ADBCmd(A3),D3; get command that completed
|
|
eieioSTP
|
|
|
|
; keep the ADB Parser program happy by updating the following variables
|
|
; They are not used by this implementation, but we fill them in with approximate
|
|
; values to make the tool happy.
|
|
|
|
eieioSTP
|
|
MOVE.B D3,fDBCmd(A3) ; last ADB command
|
|
eieioSTP
|
|
MOVE.B D3,pollCmd(A3) ; assume that it was a poll command
|
|
eieioSTP
|
|
MOVE.B D2,D2 ; copy the command zzz should this be move.b d3,d2?
|
|
LSR.B #4,D2 ; get the address
|
|
eieioSTP
|
|
MOVE.B D2,pollAddr(A3) ; assume that it was a poll address
|
|
|
|
MOVEQ #0,D2 ; zero extend the length
|
|
eieioSTP
|
|
MOVE.B RcvMsg.DataCount(A3),D2 ; get length of receive data
|
|
eieioSTP
|
|
LEA RcvMsg.ADBData(A3),A2 ; point to the data buffer
|
|
eieioSTP
|
|
BSET #fDBUseRcvMsg,fDBAuFlag(A3) ; use the receive buffer for the reply
|
|
BTST #ExplicitCmd,D0 ; see if explicit or implicit
|
|
BEQ.L ImplicitRequestDone ; if implicit
|
|
eieioSTP
|
|
BCLR #fDBExpActive,fDBAuFlag(A3) ; remember that it has completed
|
|
eieioSTP
|
|
BRA.L ExplicitRequestDone ; if explicit
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: IOPRunKBD
|
|
;
|
|
; Inputs:
|
|
;
|
|
; Outputs:
|
|
;
|
|
; Trashes:
|
|
;
|
|
; Function: code to handle keyboard polling in a debugger
|
|
;________________________________________________________________________________________
|
|
|
|
IOPRunKBD MOVE.L #(%00001000<<24)+\ ; allow xmt msg 3
|
|
(%00001000<<16)+\ ; allow rcv msg 3
|
|
(0<<8)+\ ; this byte must be zero
|
|
1,d0 ; ADB is on SWIM IOP (IOP 1)
|
|
BRA.L IOPInterrupt ; go handle the interrupt
|
|
|
|
|
|
ENDWITH ; {IOPRequestInfo}
|
|
|
|
ENDIF ; {IopADB}
|
|
|
|
|
|
|
|
;•••••••••••••••••••••••••••••••••••• Miscellaneous •••••••••••••••••••••••••••••••••••••
|
|
|
|
|
|
IF hasOrwell THEN ; <H2>
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: QuadraDebugPoll
|
|
;
|
|
; Inputs: none
|
|
;
|
|
; Outputs: none
|
|
;
|
|
; Trashes: A1, D0, D1
|
|
;
|
|
; Function: checks if the Caboose-style keyswitch is in the POWER OFF position, and if
|
|
; so, turns the system off.
|
|
;
|
|
; NOTE: A side effect of reading the keyswitch (VIA2, vBufB) is that if there
|
|
; are any pending sound interrupts, they'll be cleared in the VIA (design
|
|
; flaw?). Therefore, if there are any pending interrupts, it will diddle
|
|
; with Batman to regenerate the interrupt in the VIA.
|
|
;________________________________________________________________________________________
|
|
|
|
QuadraDebugPoll
|
|
MOVEQ #v2PowerOff,D1 ; which bit to test in VIA2 vBufB
|
|
BSR.S QuadraCheckKeyswitch ; is the keyswitch in the POWER OFF position?
|
|
BNE.S IOPRunKBD ; -> no, go do the keyboard polling
|
|
|
|
@PowerOff _PowerOff ; kill the power
|
|
BRA.S @PowerOff
|
|
|
|
|
|
;________________________________________________________________________________________
|
|
;
|
|
; Routine: QuadraCheckSecure
|
|
;
|
|
; Inputs: A3 - pointer to ADBBase
|
|
;
|
|
; Outputs: CCR - BNE: call the handler, BEQ: skip it
|
|
;
|
|
; Trashes: A1, D0, D1
|
|
;
|
|
; Function: checks if the Caboose-style keyswitch is in the SECURE position (and if so,
|
|
; the ADB Manager won't call the device completion routines)
|
|
;
|
|
; NOTE: A side effect of reading the keyswitch (VIA2, vBufB) is that if there
|
|
; are any pending sound interrupts, they'll be cleared in the VIA (design
|
|
; flaw?). Therefore, if there are any pending interrupts, it will diddle
|
|
; with Batman to regenerate the interrupt in the VIA.
|
|
;________________________________________________________________________________________
|
|
|
|
QuadraCheckSecure
|
|
MOVEQ #v2Keyswitch,D1 ; which bit to test in VIA2 vBufB
|
|
|
|
QuadraCheckKeyswitch
|
|
@switchOffset EQU $80 ; bit 7 is a don't care to the VIA2 decode
|
|
|
|
MOVEA.L VIA2,A1 ; point to VIA2
|
|
eieioSTP
|
|
MOVE.B vBufB+@switchOffset(A1),D0 ; read the keyswitch register, clearing interrupts (GAG)
|
|
eieioSTP
|
|
BTST #ifCB1,vIFR(A1) ; do we think a sound interrupt is still pending?
|
|
eieioSTP
|
|
BNE.S @HaveInt ; -> yes, we're done
|
|
|
|
MOVEA.L ASCBase,A1 ; point to Batman
|
|
CMPA.L #-1,A1 ; is it setup yet?
|
|
BEQ.S @HaveInt ; -> no, bail
|
|
|
|
MOVE SR,-(SP) ; save the status register
|
|
ORI #NoIntMask,SR ; and disable all interrupts
|
|
|
|
eieioSTP
|
|
TST.B bmIntControlA(A1) ; is the channel A interrupt enabled?
|
|
eieioSTP
|
|
BNE.S @NoChannelA ; -> no
|
|
eieioSTP
|
|
MOVE.B #1,bmIntControlA(A1) ; disable channel A interrupts,
|
|
NOP ; give Batman time to process the disable,
|
|
CLR.B bmIntControlA(A1) ; and clear the interrupt mask to regenerate
|
|
|
|
@NoChannelA
|
|
eieioSTP
|
|
TST.B bmIntControlB(A1) ; is the channel B interrupt enabled?
|
|
eieioSTP
|
|
BNE.S @NoChannelB ; -> no
|
|
eieioSTP
|
|
MOVE.B #1,bmIntControlB(A1) ; disable channel B interrupts,
|
|
NOP ; give Batman time to process the disable,
|
|
CLR.B bmIntControlB(A1) ; and clear the interrupt mask to regenerate
|
|
eieioSTP
|
|
|
|
@NoChannelB MOVE (SP)+,SR ; restore the status register
|
|
|
|
@HaveInt BTST D1,D0 ; test the bit we're interested in (0 = switch on)
|
|
RTS
|
|
|
|
|
|
ENDIF ; {hasOrwell}
|
|
|
|
|
|
END
|