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.
1392 lines
46 KiB
Plaintext
1392 lines
46 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
|