************************************************************************ ; ; File: CudaMgr.a ; ; Contains: Contains low level code to support sending and receiving ; packets (ADB, Pseudo Commands, Ticks, etc) to/from the Cuda ; 6805uC. Uses some common routines that are in EgretMgr.a and ; EgretPatches.a. The Egret/Caboose Firmware and the Cuda firmware ; use the same globals area and parameter blocks. ; ; ; Written by: Gary Rensberger ; Modified by: Gus Andrade ; Cuda Port by: Ray Montagne ; Modified by: Greg Schroeder ; ; Copyright © 1990-1993 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 11/9/93 KW added some eieioSTP macros. Only expands for CygnusX1 ROM ; 9/29/93 SAM From mc900ftjesus. ; 9/25/93 SAM Sucked over CudaDispatch from CudaMgrPatch.a (in the Gibbly). ; 6/14/93 kc Roll in Ludwig. ; 6/11/93 chp Enabling interrupts too broadly across the Cuda Manager results ; in frequent system hangs when using LocalTalk. Extensive ; performance analysis indicates that Cuda Manager interrupt ; latency is worst when calling _CudaDispatch with interrupts ; masked (see also: the Reliability Manager) and in the loop ; waiting for the first byte of a command packet to shift out of ; the VIA. SCC interrupts are now reenabled just before this wait ; loop, but not in CudaShiftRegisterIRQ. ; 5/21/93 GS (chp,mal,fau) Really fixed the LW6 fix of making sure the ; interrupt level moves from 7 back down to 3 after the first byte ; of the transaction has been moved into the Shift Reg in ; CudaDispatch. ; 5/14/93 GS Changed the interrupt level from level 3 to 7 around some time ; critical code during the sample of the TReq line and moving the ; first byte of a transaction into the SR of the VIA. ; 5/10/93 chp During Cuda transactions, disable interrupts only through level ; 3 instead of through level 6. This markedly improves handling of ; MIDI, DMA, and DSP interrupts. Fixes RADAR #1059613. Reviewed by ; God and both houses of Parliament. ; 1/28/93 mal Fixed typo where D7 used instead of D0. Fixes bug #1062496. ; 1/14/93 GS Fix a mis-typed label. ; 1/14/93 GS (RBM) Fix the occassional hang at boot. When outputing from ; the VIA to Cuda, the interrupt will occur prior to the rising ; edge of CB1. Delay long enough for the edge to occur before ; acknowledging the shift register interrupt. ; 11/20/92 GS Removed the support for the Cuda PDMsgs by removing routines ; CudaPDMPatch, CudaKeyBdSwHandler, and associated routines. This ; function is now handled by the Gibbly. ; 11/5/92 SWC Changed ShutdownEqu.a->Shutdown.a. ; 10/20/92 fau Changed CudaInit to use A2 instead of A1. This was required ; because routines in Universal.a that happenned after the call to ; CudaInit were depending on A1 being set up. ; 10/8/92 GS Added code to the KeybdSwHnadler to inhibit calls to the ; OSDispatcher if the Trap is not yet installed by the System. ; 10/7/92 GS [RBM,TJR] Added call to initialize vector in Cuda manager ; globals with pointer to the power message resume procedure. ; Added dispatch selector to execute the power message resume ; procedure. ; Needed to initialize the high word of d7 before going to ; Error1Handler. ; If interrupts get disabled while Cuda is in the process of ; generating an IDLE acknowledge, a subsequent attention byte ; could cause the IDLE acknowledge and ATTENTION byte to be ; appended into the current response packet. ; Changed the handling of response packets such that when the last ; byte has been received, the Cuda manager will wait for the IDLE ; acknowledge (should occur within 71.5΅S minimum of negation of ; TIP). ; 9/18/92 GS Re-Enable the CudaEnableKeybdNMI routine because of the Vector ; table. Cuda No longer uses this routine, but there was a vector ; set aside for it. This needs to be addressed in a later version ; of the ROM. ; 9/18/92 GS (rbm) If interrupts get disabled while Cuda is in the process ; ofgenerating an IDLE acknowledge, a subsequent attention byte ; could cause the IDLE acknowledge and ATTENTION byte to ; beappended into the current response packet. Changed the ; handling of response packets such that when the last byte has ; been received, the Cuda manager will wait for the IDLE ; acknowledge (should occur within 71.5΅S minimum of negation of ; TIP). ; (gaa/rbm) Modified CudaInit to check if Cuda was trying to start ; a transaction prior to starting the Sync Ack process. This ; fixed a bug where DeadCuda was called because the timeout would ; be reached because ; Cuda was trying to start a transaction and the system side ; thought that it was in the middle of a Sync Ack cycle. ; Update Tickle Timer to 160 count. Decr Timer in Cuda FW is at ; 16cnts/sec. ; Remove Completion routine in TickleCuda routine. ; 8/24/92 GS Added code in the IRQDispatcher to fix the bug that passed back ; data in a Read6805 request, when the data bytes reqquessted was ; zero. The fix will chk the recvDataCnt var of the Parm blk before ; placing data in the recv buffer ptr. ; 6/30/92 GS Fixed a problem in the Cuda Dispatcher. If a collision occurs, ; wait for the busy state flag to be cleared by the IdleAck ; handler before accepting another command. This problem causes ; the ADB transactions to get out of sync and the system will ; hang. ; 6/26/92 GS (RBM) Updated 'SetTransferParams' so that special setup for ; 'RdWrIIC' is performed. This command requires a non conforming ; parameter ; block in that the EgretPB.ByteCnt requires the number of bytes ; to send prior to the data portion of the IIC transaction and ; EgretPB.BufPtr points to a pString. On write, the pString ; contains the data to write while on read operations, the pString ; contains only a count of bytes to read. Data is then returned ; inthe pString. ; Removed Cuda Cmds to enable Keyboard NMI, and IIC mode. These ; are no longer need, because KeyboardNMI now defaults to Enabled. ; SetDFACorIIC mode is no longer a command. IIC and DFAC both use ; use the Data and Clk pins in the same mode. ; EnableWakeUpMode is now done with a CDev. ; ; 5/25/92 RB Removed definition of 'CUDA' since it has a conflict with ; another symbol and it is not used anyway. Also got rid of ; 'branch to next instruction warning. ; <1> 5/22/92 RB first checked in ; 5/21/92 RB First Checked in. Got rid of OverPatch area and PadForOverPatch ; conditionals. ; 3/23/92 GS Fixed bug in code rolled in from the Regatta System files in ; the CudaShiftRegIRQ routine. Incorrectly, entered the ; tickcompletion routine with bogus values then placed into the ; TIME lomem ; 3/3/92 GS Updated the INIT of Cuda to include the IIC and Wakeup modes. ; Also added the Enable Keybd NMI cmd to CudaINIT. ; 2/10/92 GS Cleaned up some comments. Must return here to add in code for ; checks of the use of DFAC or IIC mode used on Cuda depending on ; machine type. ; <1> 1/16/92 GS first checked in ; ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; Pre-Pandora ROM comments begin here. ; ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; Previous history ; ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ ; Changes for Cuda: ; {9} 08/21/91 gjs added patch to align code in Egret/Cuda Dispatch code. Patch ; placed in CudaPatches.a ; {8} 07/30/91 gjs Preserved/Restored status register on calls to the completion ; routines in ShiftRegIRQ routine at @Implicit, and at routine ; delay100us ; {7} 07/03/91 gjs Overpatched the CudaInit code into CudaPatchesToo.a ; added Export DeadCuda ; {6} 06/24/91 gjs Rolled the Cuda Manager changes into Terror ; <5> 2/20/91 BG Fixed error in CheckPacket. The check for allowable ; pseudo-packets was a hard-coded name check instead of an ; end-of-table check. ; <4> 12/11/90 JJ Mac LC: Changes references to VISAChipBit to V8ChipBit. ; <3> 12/7/90 CCH Adjusted the patch code in CheckPacket so that it fits in the ; same number of bytes as the original code. ; <2> 12/6/90 BG (with GA) Rolled in Eclipse-related Egret/Caboose changes. ; ; <01> 12/6/90 RBM Ported Cuda manager from Egret manager . ; Due to major changes in the transaction protocol, Egret is no longer supported. ; ROM builds should include IF HasCUDA for startinit & diagnostics. ; Changed handshake protocol to implement CUDA. Eliminated timed ; assertions/negations & inverted polarity of handshake lines that ; are controlled by the system. Handshake line signal names have ; been changed to avoid confusion in usage. Added an Idle State ; acknowledgement after termination of a response packet transaction. ; Exit from ShiftRegIrq now restores the interrupt mask on exit from ; transmission of command packet data. ; ; Restructured code in ShiftRegIrq so that testing the TReq handshake ; line does not occur after manipulation of TIP or ByteAck. ; ; CudaInit no longer needs to send a NOP command to turn off the ; asynchronous transaction sources on ReBoot. This function is ; performed through a 'SYNC' handshake sequence which disables ; all asynchronous message sources. ; ; Exported routines are in a jump table so that any future overpatching ; may be a little easier to implement. ; ************************************************************************ machine mc68020 BLANKS ON STRING ASIS PRINT OFF LOAD 'StandardEqu.d' INCLUDE 'HardwarePrivateEqu.a' INCLUDE 'UniversalEqu.a' INCLUDE 'DebugMonEqu.a' INCLUDE 'ShutDown.a' include 'EgretEqu.a' PRINT ON eject CudaMgr PROC EXPORT ; { CudaMgr Proc EXPORT CudaDispatch, SendCudaCmd, CudaInit EXPORT CudaTickHandler, CudaShiftRegIRQ IMPORT GetHardwareInfo, Error1Handler IMPORT SetResponseParams, CheckPacket IMPORT PseudoCntTable,ADBCntTable CudaDebug EQU 1 ; Enables Debug features during development ErrCudaInit equ $0030 ; TEMPORARY definition of error equate defined in STEQU.a WITH EgretGlobals,EgretPB,RespHeader eject ; { With ;________________________________________________________________________________________________ ; Routine: CudaDispatch 8f90 ; ; Function: This is the Cuda manager trap routine. It waits for Cuda to be idle, sends ; the first byte of the command packet. If Cuda didn't abort, then it sets up ; globals for the IRQ handler, and if a completion routine was specified, it returns ; back to the caller. If no completion routine, then it waits synchronously for ; the command/response to finish, using the busy bit. When the IRQ handler has finished ; the response packet, it preps the globals to expect an auto-response packet ; (ticks or ADB), clears 'busy' and calls the completion routine (if any). ; ; Inputs: a0 - pointer to parameter block as followsΙ ; ; pbPacketType dc.b ; pbCmd dc.b ; pbParam dc.b ; dc.b ; dc.b ; dc.b ; pbByteCnt dc.w ; pbBufPtr dc.l ; pbFlags dc.b ; dc.b ; pbResult dc.w ; pbCompletion dc.l ; ; Outputs: d0 - result (0 for now) ; ; Destroys: a0-a2, d0-d1 ;________________________________________________________________________________________________ CudaDispatch jsr CheckCudaPacket ; Validate the Packet type & command byte tst.w pbResult(a0) ; is packet ok? bne @done ; Exit if Error packet movea.l EgretBase,a2 ; a2 gets ptr to globals movea.l VIA,a1 ; a1 points to VIA base cmpi.b #specialPkt,pbCmdType(a0) ; is this a special command? bne.s @ckPDMInit ; check for Eclipse PowerDown Message Initialization move.l a0,ADBpb(a2) ; yes, is to set the ADB param block (for autopoll data). bra @done @ckPDMInit cmpi.b #PDMVectPkt,pbCmdType(a0) ; check for PowerDown message vector Init bne.s @ckContInit move.l pbParam(a0),PDMComp(a2) ; handler for Eclipse PowerDown Message Packet bra @done @ckContInit cmpi.b #ContinueVectPkt,pbCmdType(a0) ; check for PowerDown message vector Init bne.s @ckDoCont move.l pbParam(a0),ContinueComp(a2) ; handler for power message continue procedure bra @done @ckDoCont cmpi.b #DoContinueProc,pbCmdType(a0) ; check for PowerDown message vector Init bne.s @CudaRestart ; Must be Egret Command tst.l ContinueComp(a2) ; is there a continue procedure? beq @done ; no, then do nothing lea ContinueComp(a2),a2 move.l (a2),a2 jsr (a2) ; else, execute the continue procedure bra @done @CudaRestart CmpI #$10C, (A0) BEQ.B @L4 CmpI #$107, (A0) BNE.B @endChicanery Tst.B $64(A2) BEQ @endChicanery @L4 CmpI #$100, $2(A0) BLT.B @L5 Move #$FFCE, $E(A0) Bra @done @L5 Lea.L $66(A2), A2 Move $6(A0), D1 BEQ @L9 SubQ #$1, D1 MoveQ.L #$0, D2 Move $2(A0), D2 MoveA.L $8(A0), A1 @L6 CmpI.B #$7, $1(A0) BEQ.B @L7 Move.B (A1)+, $0(A2,D2.W) Bra.B @L8 @L7 Move.B $0(A2,D2.W), (A1)+ @L8 AddQ #$1, D2 AndI #$FF, D2 DBF D1, @L6 @L9 MoveA.L ($DE0), A2 MoveA.L ($1D4), A1 CmpI.B #$C, $1(A0) BEQ.B @endChicanery Tst.L $10(A0) BEQ @done MoveA.L $10(A0), A1 Jsr (A1) Bra @done @endChicanery move.w sr,-(sp) ; save SR ori.w #hiIntMask,sr ; mask interrupts eieioSTP btst.b #TReq,vBufB(a1) ; does Cuda want to abort? eieioSTP beq.s @abort ; yes, wait for it to go away btst.b #busy,flags(a2) ; has an idle acknowledge occured? bne.s @abort ; no, then wait for it! bset.b #busy,flags(a2) ; not an abort, mark that we're busy. beq.s @sendPackType ; we were not busy before, so try to send the first byte @abort move.w (sp)+,sr ; we were busy, enable interrupts jsr pollByte ; poll shift reg, calling handler if interrupts masked bra.s @endChicanery ; and keep waiting for busy to go away... @sendPackType ; interrupts masked here eieioSTP bset.b #SRdir,vACR(a1) ; switch to output, Define direction FROM System nop eieioSTP move.b pbCmdType(a0),vSR(a1) ; send command packet to shift reg nop eieioSTP bset.b #vByteAck,vBufB(a1) ; make sure state is idle before transaction nop eieioSTP bclr.b #TIP,vBufB(a1) ; assert TIP (we're starting command packet) nop eieioSTP ; ; If PollProc exists, Poll the SCC and save any available data ; When the shift register irq comes in call the PollProc ; then process the shift register irq data ; movem.l d0-d3/a0-a4/a6,-(sp) ; save some registers move.l PollStack,-(sp) ; save previous poll stack lea @zero, a3 move.l sp,PollStack ; Pointer to buffer for polled bytes ; btst.b #0,SccIopFlag ; Check if we are in IOP mode (On Eclipse...) ; beq.s @wait tst.l PollProc ; Check for a Poll Proc available beq.s @wait ; movea.l SccRd,a3 ; SCC may have data to get movea.l a3,a6 addq.l #Actl,a3 ; Point to data available register (RR0) addq.l #AData,a6 ; Point to the SCC data register @wait btst.b #RxCa,(a3) ; Test for SCC data available beq.s @2 move.b (a6),-(sp) ; Push the data on the stack @2 bsr.l otherDelay eieioSTP btst.b #vShift,vIFR(a1) ; now wait for shift reg IRQ eieioSTP beq.s @wait cmpa.l PollStack,SP ; Is there any poll data beq.s @NoSCCData ; ; We have SCC data and a Poll Proc to call. Go call it ; pea @NoSCCData ; Return addr for PollProc move.l PollProc,-(SP) ; Point to the PollProc rts ; Call the PollProc @zero dc.w 0 @NoSCCData move.l (sp)+,PollStack ; restore previous poll stack movem.l (sp)+,d0-d3/a0-a4/a6 ; restore work registers eieioSTP btst.b #TReq,vBufB(a1) ; did CUDA abort? eieioSTP bne.s @accepted ; no, then it will accept our packet ;----------------------------------------------------------------------------------------------- ; Note that changing the VIA mode can generate an edge internal to the VIA which will ; increment the bit count for the next byte to be shifted. ; When outputing from the VIA to Cuda, the interrupt will occur prior to the rising edge ; of CB1. Delay long enough for the edge to occur before acknowledging the shift ; register interrupt. (R. Montagne 1/11/93) ;________________________________________________________________________________________________ move $d00,d0 divu #$50,d0 @mode7delay dbra d0,@mode7delay eieioSTP bclr.b #SRdir,vACR(a1) ; yes, switch back to input nop eieioSTP tst.b vSR(a1) ; clear pending shift register interrupt nop eieioSTP ori.b #((1< btst.b #vShift,vIFR(a1) bne.s @output move.w d3,sr ; restore interrupts rts ;________________________________________________________________________________________________ ; When outputing from the VIA to Cuda, the interrupt will occur prior to the rising edge ; of CB1. Delay long enough for the edge to occur before acknowledging the shift ; register interrupt. (R. Montagne 1/11/93) ;________________________________________________________________________________________________ @output movea.l EgretBase,a2 ; get ptr to globals <13> bset.b #busy,flags(a2) ; make sure we're marked as busy btst.b #$4, $1600(A1) beq.s * + $60 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; move $d00,d0 divu #$50,d0 @mode7delay dbra d0,@mode7delay ; eieioSTP tst.b vSR(a1) ; clear the shift reg interrupt nop eieioSTP tst.w sendHdrCnt(a2) ; any bytes left in header? ble.s @ckSendData ; no, see if any send bytes left... movea.l sendHdrPtr(a2),a0 ; get ptr to header move.b (a0)+,d0 ; get next header byte move.l a0,sendHdrPtr(a2) ; and update header ptr bsr SendByte ; send the byte subq.w #1,sendHdrCnt(a2) ; count it bra @exit ; and exit @ckSendData tst.w sendDataCnt(a2) ; any bytes left in data to send ble.s @CmdFinished ; no, then we're finished with command packet movea.l sendDataPtr(a2),a0 ; get current data ptr move.b (a0)+,d0 ; yes, get next data byte move.l a0,sendDataPtr(a2) ; and update the ptr bsr SendByte ; send it subq.w #1,sendDataCnt(a2) ; count it bra @exit ; and exit @CmdFinished eieioSTP bclr.b #SRdir,vACR(a1) ; now switch to input nop eieioSTP ;________________________________________________________________________________________________ ; When changing VIA direction, a clock can be generated to the VIA bit counter. An ; access to the shift data register will keep the counter in sync with the communications ; protocol to Cuda. ;________________________________________________________________________________________________ eieioSTP tst.b vSR(a1) ; make sure VIA counter is in sync eieioSTP @sendCmd eieioSTP ori.b #((1< movea.l rcvDataPtr(a2),a0 ; get ptr to receive data buffer beq.s @zeroReq ; yes, don't pass any data back move.b d0,(a0)+ ; store the data byte @zeroReq eieioSTP btst.b #TREQ,vBufB(a1) ; was this the last byte? eieioSTP bne @lastIrq ; yes, terminate response packet move.l a0,rcvDataPtr(a2) ; and update data ptr subq.w #1,rcvDataCnt(a2) ; count it bgt.s @ack ; not last, normal acknowlege btst.b #openData,flags(a2) ; is this an open ended data packet? bne.s @lastIrq ; and we're done @ack tst.w rcvDataCnt(a2) ; any receive data bytes to get? ble @lastIrq ; no, then terminate transaction and exit @ackHdr move.b vBufB(a1),d0 ; get current handshake state andi.b #((1< (rbm) ; Now that the response transaction has been terminated, let's wait for the idle (rbm) ; acknowledge interrupt to occur. This should happen about 71.5 ΅S after the negation (rbm) ; of TIP. This will prevent any problem related to interrupts being masked during the (rbm) ; transmission of the idle acknowledge when another asynchronous Cuda transaction is to (rbm) ; begin while interrupts are masked (as may happen during disc access while moving the (rbm) ; mouse). (rbm) ; (rbm) @waitIdleAck ; (rbm) eieioSTP bsr.l otherDelay btst.b #ifSR,vIFR(a1) ; wait for idle state acknowledgement (rbm) eieioSTP beq.s @waitIdleAck ; (rbm) eieioSTP tst.b vSR(a1) ; clear the shift reg interrupt (rbm) nop eieioSTP ;--------------------------------------------------------------------------- @done movea.l curPb(a2),a0 ; a0 points to current param block lea rcvHeader(a2),a1 ; a1 points to header buffer eieioSTP cmp.b #ErrorPkt,1(a1) ; check for Error response packet eieioSTP bne.s @NotError ; ; The current transaction generated an Error <11> ; move.l 1(a1),pbParam(a0) ; Return the Error Response packet to the caller (dont include attn byte) move.w #paramErr,pbResult(a0) ; and return a parameter block error @NotError cmpa.l adbPb(a2),a0 ; was this an implicit command? beq.s @implicit ; yes, handle autopoll/tick packet tst.b 1(a1) ; is this an ADB response? bne.s @ckComp ; no, then data already transfered, call completion @adbResp cmpa.l adbPb(a2),a0 ; is this autopoll data bne.s @skip ; no, don't fix ray's flag bset.b #EgAutoPoll,2(a1) ; yes, fix em @skip btst.b #EgAutoPoll,2(a1) ; check status, is this AutoPoll data? bne @ckAutoPollComp ; yes, handle if we have completion routine move.b 2(a1),pbFlags(a0) ; explicit ADB command, stuff flags byte move.w rcvHdrIndex(a2),d0 ; get header+data byte count subq.w #4,d0 ; - header bytes beq.s @dontupdate ; if no data received don't update the byte count move.w d0,pbByteCnt(a0) ; stuff data byte count @dontupdate move.l pbBufPtr(a0),a2 ; get users buffer ptr addq.w #4,a1 ; point at the data bra.s @cnt @xfer move.b (a1)+,(a2)+ ; copy the byte @cnt dbra d0,@xfer ; repeat for all bytes move.l EgretBase,a2 ; get globals ptr again @ckComp move.l pbCompletion(a0),d0 ; any completion routine? beq @exitNoComp ; no, just exit move.l d0,a1 ; yes, get it's address move.l a0,-(sp) ; save param block ptr bigjsr SetResponseParams,a3 ; setup globals to handle auto response packets again move.w d3,sr ; restore interrupts move.l (sp)+,a0 ; restore param block ptr move.w sr,-(sp) ; save register for completion routines that trash it jsr (a1) ; and call it move.w (sp)+,sr ; rts ; ;-------------------------------------------------------------------------------------------- ; AutoPoll or Tick data, push it on stack and call completion rtn @implicit tst.b RespPktType(a1) ; is this an ADB response? beq.s @ckAutoPollComp ; yes, handle it cmpi.b #tickPkt,RespPktType(a1) ; is this a short tick response? beq.s @ckTickComp ; yes, handle it (has no param block) cmpi.b #pseudoPkt,RespPktType(a1) ; no, should be pseudo command tick response ; ShiftRegIRQPatch from EgretPatchesToo.a bne.s @ckPDM ; check for PowerDown Message (Eclipse ONLY) cmpi.b #RdTime,RespCmd(a1) ; yes, it should be read time bne.s @exitNoComp ; if not read time ignore the transaction (SHOULD NOT HAPPEN!!) bra.s @ckTickComp ; otherwise, push response packet on stack, call it. ; >>CONTINUE original routine ;----------------------------------------------- ; Eclipse Check for PowerDown Message ; @ckPDM cmpi.b #PDMPkt,RespPktType(a1) ; check for PowerDown Message Packet type bne.s @exitNoComp ; None of the above Packets ignore it (SHOULD NOT HAPPEN) ; if it does EGRET is Very SICK!! ; ; For PDM packets check for service routine address and ; call it if one exists. ; move.l PDMComp(a2),d2 ; get the completion routine address beq.s @exitNoComp ; go away if vector is null bigjsr SetResponseParams,a3 ; setup globals to handle auto response packets again move.l d2,a3 ; call the Service routine move.b RespCmd(a1),d0 ; get the powerDown Switch destination position move.w sr,d3 ; save interrupts jsr (a3) move.w d3,sr ; restore interrupts bra.s @exit ; done, now exit ; end ShiftRegIRQPatch EgretPatchesToo.a @ckTickComp ; tick data, check for completion routine move.l tickComp(a2),d2 ; get completion routine in d2 beq.s @exitNoComp ; none specified, just exit bra.s @push ; otherwise, push response packet on stack, call it. @ckAutoPollComp ; ADB autopoll data, check for completion rtn bset.b #EgAutoPoll,2(a1) ; Set AutoPoll bit to fix bug in old Egret parts tst.l a0 ; do we really have a current param block? (we should) beq.s @exitNoComp ; no, exit move.l pbCompletion(a0),d2 ; any completion routine? (keep in d2) beq.s @exitNoComp ; no, just exit @push suba.w #12,sp ; allocate 12 byte buffer on stack movea.l sp,a2 ; point to the buffer move.l (a1)+,(a2)+ ; copy response header onto stack move.l (a1)+,(a2)+ ; copy response data onto stack move.l (a1)+,(a2)+ ; copy response data onto stack movea.l EgretBase,a2 ; restore ptr to globals move.w rcvHdrIndex(a2),d0 ; d0 = # bytes in response header subq.w #4,d0 ; byte count = # data bytes (strip off header bytes) bigjsr SetResponseParams,a3 ; setup globals to handle auto response packets again move.w d3,sr ; restore interrupts move.l sp,a1 ; a1 = ptr to response packet addq.l #2,a1 ; a1 = ptr to status flag move.l d2,a3 ; get completion routine ; ; ₯₯₯₯₯ Calling Completion Routine ₯₯₯₯₯ ; ; a0 = Pointer to parameter block ; a1 = Pointer to status flag in response packet (Cuda Transaction Format) ; a2 = Pointer to Cuda Globals ; d0 = Number of bytes in response packet, excluding Attention, Type, Flags & Command. ; move.w d3, -(sp) ; preserve status reg during completion routine {8} jsr (a3) ; call it (a0 points to param block for ADB) move.w (sp)+, d3 ; restore status reg adda.w #12,sp ; pop buffer rts @exitNoComp ; no completion routine specified, bigjsr SetResponseParams,a3 ; setup globals to handle auto response packets again @exit ; move.w d3,sr ; restore interrupts rts Eject ;________________________________________________________________________________________________ ; Routine: SetTransferParams 93e0 ; ; Function: This routine sets up transmit/receive ptrs (globals) for the packet pointed to by A0, ; for use by the Shift Reg interrupt handler. ; ; Inputs: a0 - Param block pointer ; a1 - VIA ; a2 - Ptr to globals (EgretBase) ; ; Outputs: none ; Destroys: d0,d1 ;________________________________________________________________________________________________ ; Export SetTransferParams SetTransferParams move.l a1,-(sp) ; save a1 lea pbCmd(a0),a1 move.l a1,sendHdrPtr(a2) ; point to 1st byte of header to send moveq #0,d0 move.b pbCmd(a0),d0 ; get command tst.b pbCmdType(a0) ; is this an ADB command? bne.s @pseudo ; no, must be a pseudo command andi.b #%00001111,d0 ; keep low 4 bits biglea ADBCntTable,a1 ; get ptr to our ADB command table bra @check ; and look up our send/rcv byte counts ; ; Pseudo Command. Now Check for SEND DFAC and treat as special case if it is. <12> ; On DFAC, use the byte count in the parameter block as the count to send <12> ; to Egret instead the count contained in the PseudoCntTable. <12> ; @pseudo cmp.b #WrDFAC,pbCmd(a0) ; check for DFAC <12> bne.s @notDFAC ; use the table if not DFAC <12> move.w pbByteCnt(a0),d1 ; was Write DFAC use the byte count in the pBlock <12> addq.w #1,d1 ; include the packet byte already sent <12> move.w d1,sendHdrCnt(a2) ; set up header byte count <12> clr.w sendDataCnt(a2) ; no extended data bytes <12> clr.l sendDataPtr(a2) ; no extended data ptr <12> bra @rcvParams @notDFAC cmp.b #$25,pbCmd(a0) beq @dontjump cmp.b #RdWrIIC,pbCmd(a0) ; check for IIC transaction bne.s @notRdWrIIC ; use the table if not RdWrIIC * * Here is how the transfer globals are set up for IIC transactionsΙ * * _Parameter______ _RdWrIIC_(write)_____________ _Parameter______ _RdWrIIC_(read)______________ * CudaPB CudaPB * pbCmdType pseudoPkt pbCmdType pseudoPkt * pbCmd RdWrIIC pbCmd RdWrIIC * pbParam[0] IIC Device Addr. pbParam[0] IIC Device Addr. * pbParam[1] IIC Register Addr. (optional) pbParam[1] IIC Register Addr. (optional) * pbParam[2] ₯ pbParam[2] ₯ * pbParam[3] ₯ pbParam[3] ₯ * pbByteCnt # fields in pbParam array pbByteCnt # fields in pbParam array * pbBufPtr myBuffer pbBufPtr myBuffer * pbFlags ₯ pbFlags ₯ * pbSpare ₯ pbSpare ₯ * pbResult ₯ pbResult ₯ * pbCompletion NIL pbCompletion NIL * SendHdrCnt CudaPB.pbByteCnt SendHdrCnt CudaPB.pbByteCnt * SendHdrPtr &CudaPB.pbCmd SendHdrPtr &CudaPB.pbCmd * SendDataCnt (char)myBuffer[0] SendDataCnt 0 * SendDataPtr &myBuffer[1] SendDataPtr NIL * RcvHdrCnt 4+0 RcvHdrCnt 4+0 * RcvHdrIndex 0 RcvHdrIndex 0 * RcvDataCnt 0 RcvDataCnt (char)myBuffer[0] * RcvDataPtr &myBuffer[1] RcvDataPtr &myBuffer[1] * RcvHeader RcvHeader * RespAttn ₯ RespAttn ₯ * RespType ₯ RespType ₯ * RespFlags ₯ RespFlags ₯ * RespCmd ₯ RespCmd ₯ * RespData ₯ RespData ₯ * curPB CudaPB curPB CudaPB * @dontjump move.w pbByteCnt(a0),d1 ; RdWrIIC uses byte count for send portion addq.w #1,d1 ; include the packet byte already sent move.w d1,sendHdrCnt(a2) ; set up header byte count move.w #4,rcvHdrCnt(a2) ; 4 byte header default clr.w rcvHdrIndex(a2) ; reset index into header buffer move.l pbBufPtr(a0),a1 ; get address of data buffer cmp.b #RdWrIIC,pbCmd(a0) beq.s @doIICwrite btst.b #0,4(a0) bne.s @doIICread @doIICwrite ; btst.b #0,pbParam(a0) bne.s @doIICread moveq #0,d1 ; data phase count must be 1 to 256 move.b (a1),d1 ; bne.s @wrCntOK ; move.w #$0100,d1 ; @wrCntOK ; move.w d1,sendDataCnt(a2) ; number of extended data bytes to send @newlbl adda.l #1,a1 ; move.l a1,sendDataPtr(a2) ; extended data ptr clr.w rcvDataCnt(a2) ; no data to receive on IIC write move.l a1,rcvDataPtr(a2) ; but let's point at xmit buffer to be safe bra.s @RdWrIICexit ; @doIICread ; clr.w sendDataCnt(a2) ; no extended data bytes to send clr.l sendDataPtr(a2) ; no extended data ptr moveq #0,d1 ; data phase count must be 1 to 256 move.b (a1),d1 ; bne.s @rdCntOK ; move.w #$0100,d1 ; @rdCntOK ; move.w d1,rcvDataCnt(a2) ; number of extended data bytes to receive adda.l #1,a1 ; move.l a1,rcvDataPtr(a2) ; extended data ptr @RdWrIICexit ; bset.b #openData,flags(a2) ; open ended data packet (RdWrIIC) bra.s @exit ; @notRdWrIIC ; biglea PseudoCntTable,a1 ; get ptr to our pseudo command table @check lsl.w #1,d0 ; x 2 for word table move.w (a1,d0.w),d1 ; get send/rcv byte counts for this command ror.w #8,d1 ; get send byte count in low byte tst.b d1 ; is this an open-ended send command? bmi.s @sendExt ; yes, branch... move.b d1,d0 ; get byte count from table ext.w d0 ; extend to word addq.b #1,d0 ; data bytes + 1 = header byte count move.w d0,sendHdrCnt(a2) ; set up header byte count clr.w sendDataCnt(a2) ; no extended data bytes clr.l sendDataPtr(a2) ; no extended data ptr bra.s @rcvParams ; now setup receive ptrs @sendExt moveq #$7F,d0 ; prepare to mask sign and.w d1,d0 ; get rid of sign addq.w #1,d0 ; + 1 for command (packet type already sent) move.w d0,sendHdrCnt(a2) ; set up header byte count move.w pbByteCnt(a0),sendDataCnt(a2) ; set up data byte count move.l pbBufPtr(a0),sendDataPtr(a2) ; set up send data ptr @rcvParams clr.w rcvHdrIndex(a2) ; reset index into header buffer move.w #4,rcvHdrCnt(a2) ; 4 byte header default asr.w #8,d1 ; get receive data byte count bmi.s @rcvExt ; branch for open-ended reads tst.b pbCmdType(a0) ; reading, is this a pseudo command? beq.s @rcvADB ; no, must be adb data lea pbParam(a0),a1 ; pseudo data will be received in pbParam move.l a1,rcvDataPtr(a2) move.w d1,rcvDataCnt(a2) ; get receive count from table bra.s @exit ; and exit @rcvADB add.w d1,rcvHdrCnt(a2) ; total header bytes = 4 + ADB data clr.w rcvDataCnt(a2) ; not used bclr.b #openData,flags(a2) ; this is not an open ended data packet (readPram, read6805) bra.s @exit @rcvExt move.w pbByteCnt(a0),rcvDataCnt(a2) ; set up received data byte count move.l pbBufPtr(a0),rcvDataPtr(a2) ; set up received data buffer ptr bset.b #openData,flags(a2) ; this is an open ended data packet (readPram, read6805) @exit move.l a0,curPb(a2) ; set up current param block movea.l (sp)+,a1 ; restore a1 rts ;_______________________________________________________________________ ; ; Routine: CheckPacketPatch ; a0 = pointer to parameter block ; Exit: z = 1 if packet type within bounds ; z ­ 1 if packet type not within bounds ;_______________________________________________________________________ CheckCudaPacket moveq #0,d0 ; pre clear the register <17>rbm move.b pbCmdType(a0),d0 ; get the command byte <17>rbm beq.s @okExit ; if it is an ADB command, continue <17>rbm cmp.w #DoContinueProc,d0 ; is this one of the special packets? <17>rbm blt.s @notSpecial ; no, error <17>rbm @OkExit move.w #0,pbResult(a0) ; no error returned in parameter block <17>rbm rts ; <17>rbm @notSpecial cmp.w #pseudoPkt,d0 ; is it a standard packet <17>rbm bne.s @BadExit ; yes, do it <17>rbm cmp.b #MaxPseudoCmd,pbCmd(a0) ; is it a valid pseudo command? <17>rbm bls.s @OkExit ; yes <17>rbm move.w #InvPseudo,pbParam(a0) ; report a pseudo command error bra.s @errorExit @BadExit move.w #InvPkt,pbParam(a0) ; report invalid packet type <17>rbm @errorExit move.w pbCmdType(a0),pbParam+2(a0) ; we are faking an error packet <17>rbm move.w #paramErr,pbResult(a0) ; parameter error in result field <17>rbm rts ;________________________________________________________________________________________________ ; Routine: CudaTickHandler 9566 ; ; Function: This is the completion routine for tick response packets. ; ; Inputs: d0 - number of bytes in response packet ; a1 - pointer to status flag ; a2 - ptr to globals ; (sp) - points to response packet ; ; Outputs: none ; ; Destroys: ??? ; ; This routine is from the Regatta Patches file PatchIIciROM.a ;---------------------------------------------------------------------------------------------------- ; This patch fixes a bug in Egret Manager TickHandler routine. <89><101> ; The routine will store the 32 bit time passed by Egret to the ; system if the packet is a ReadRealTime into TIME lowmen. ; Decrements the lowmem Time by one to compensate for the interrupt ; Handler incrementing it by one and then calls the LVL1DT interrupt ; handler. ; If the packet is a tick packet then it calls LVL1DT to increment the ; time setting and check the alarm state. ; ; Entry: ; A1.l = Points at Response data buffer At Flags byte: ; ; +---------+----------+---------+---------+---------//-------+ ; | Attn | Pkt Type | Flags | Pkt Cmd | 8 Bytes data Max | ; +---------+----------+---------+---------+---------//-------+ ; ; A2.l = Points at Egret Manager Globals ; ;---------------------------------------------------------------------------------------------------- ;________________________________________________________________________________________________ CudaTickHandler WITH respPacket,EgretGlobals ; { subq.l #2,a1 ; point to the beginning of the Response data buffer cmpi.b #TickPkt,RespType(a1) ; Check the Packet type beq.s @CallLVL1DT ; If tick packet just call LVL1DT handler ; ; The packet was a readTime packet from Egret. Update the Time lowmem and ; adjust it to compensate for the increment in the LVL1DT handler. ; move.l RespData(a1),Time ; write the new time in lowmem TIME subq.l #1,Time ; adjust to compensate for increment in LVL1DT ; ; JUMP to routine pointed to by the Contents of LVL1DT ; @CallLVL1DT move.l VIA,a1 ; point to the VIA move.l LVL1DT,a0 ; get vector eieioSTP jmp (a0) eieioSTP ENDWITH ; } ;========================================================================= ; Routine: CudaInit 9584 ; ; This routine sends a NOP/WarmStart command to Cuda. This routine is ; called early during rom Startup to stop autopoll and 1 sec irq. Also, ; the routine will issue a Send DFAC command to Cuda to initialize the ; the DFAC hardware to a known state. The routine does not use ANY ; memory it is register driven only. ; ; Inputs: NONE ; ; Outputs: NONE ; ; Destroys: D0, D1, D2, D3, A1, A5, A6, A4 (Egret 2 implementation) ; Destroys: D0, D3, A2, A5, A6 (Egret 3 implementation) ; ; NOTE: This routine is called via a BSR6 and returns via a RTS6 ;------------------------------------------------------------------------- ; ; The following sequence synchronizes Cuda to the system by disabling all asynchronous transaction ; sources (Auto Poll Data, RTC & Power Messages) and insures that no data (full or partial byte) ; is pending in the VIA data shift register. ByteAck is asserted with TIP negated. Cuda responds ; by asserting TReq and sends a byte to generate a VIA shift register interrupt. After the ; interrupt occurs, ByteAck is negated. Cuda responds by negating TReq and then delays 25΅S prior ; to sending an idle acknowledge. The VIA shift register interrupt must be cleared within 25΅S of ; the negation of TReq by Cuda. Once the idle acknowledge interrupt occurs, the VIA shift register ; interrupt is cleared and Cuda is ready to accept commands. No collisions should be possible ; until an asynchronous transaction source is enabled. ; ___________________________________________________________ ; ___ | ; TIP __|........................................................ ; _______ ___________________________ ; | | | ; ByteAck __| |_______________________| ; ___________________________________________________________ ; ________ |||||||| |||||||| ; ViaClk |||||||| |||||||| ; ___________________________________________________________ ; ; ViaData ........................................................... ; _____ _______ ______ ; | | sync | | idle | ; VIA_IRQ _____|_____________________| ack |___________| ack |____ ; ___________________________________ __________________ ____ ; _____ | | ; ViaRD | | ; ___________ ________________________ ; ____ | | ; TREQ ___________|______________________| ; ;------------------------------------------------------------------------- CudaInit movea.l DecoderInfo.VIA1Addr(a0),a2 ; get VIA 1 base address eieioSTP ori.b #((1< (1< nop eieioSTP move.l #hw4msDelay,d4 ; we want to delay 4 millisecs for ADB reset to complete @killtime eieioSTP tst.b vBufB(a2) ; eieioSTP dbra d4,@killtime ; eieioSTP btst.b #TReq,vBufB(a2) ; is Cuda starting a transaction??? eieioSTP bne.s @noX ; no, then continue with SyncAck move.l #hw4msDelay,d4 ; we want to delay 4 millisecs for ADB reset to complete @asyncByte eieioSTP btst.b #ifSR,vIFR(a2) ; else, wait for that lil' interrupt to occur eieioSTP bne.s @noX ; dbra d4,@asyncByte ; @noX eieioSTP tst.b vSR(a2) ; clear the pending interrupt nop eieioSTP move.l #hw10msDelay,d4 ; Timeout values must exceed duration of maximum ADB auto poll. <7> eieioSTP bclr.b #vByteAck,vBufB(a2) ; issue a sync state (TIP = negated, ByteAck = asserted) nop eieioSTP @waitSync eieioSTP btst.b #TReq,vBufB(a2) ; wait for sync acknowledge eieioSTP beq.s @syncAck ; dbra.w d4,@waitSync ; bra.l DeadCuda ; go play death chimes @syncAck move.l #hw10msDelay,d4 ; number of retries before giving up with Cuda @wSyncIrq eieioSTP btst.b #ifSR,vIFR(a2) ; wait for sync acknowledge interrupt eieioSTP bne.s @haveSync ; dbra.w d4,@wSyncIrq ; @haveSync move.l #hw10msDelay,d4 ; number of retries before giving up with Cuda eieioSTP bset.b #vByteAck,vBufB(a2) ; terminate the sync cycle nop eieioSTP @syncTerm eieioSTP btst.b #TReq,vBufB(a2) ; wait for sync termination acknowledge eieioSTP bne.s @haveTerm ; dbra.w d4,@syncTerm ; bra.l DeadCuda ; go play death chimes @haveTerm eieioSTP tst.b vSR(a2) ; clear the pending interrupt nop eieioSTP move.l #hw10msDelay,d4 ; number of retries before giving up with Cuda @waitIdle2 eieioSTP btst.b #ifSR,vIFR(a2) ; wait for sync termination acknowledge eieioSTP bne.w @haveIdle ; dbra.w d4,@waitIdle2 ; bra.l DeadCuda ; go play death chimes @haveIdle ; eieioSTP ori.b #((1< nop eieioSTP tst.b vSR(a2) ; clear the pending interrupt nop eieioSTP @exit rts6 ; setup the return to caller of CudaInit eject ************************************************************************************************************ * SendCudaCmd 9630: This register based routine will send up to four bytes of data to * Cuda. The packet type, command, byte count and data are passed in * registers. The routine will return with d0.w = $0000 if it sent the * command successfully. A value of $FFFF signifies that the command did * not get through. The system and Cuda hung and the system aborted the * transaction. * * WARNING: This routine will not error check the transaction requested. It is the * WARNING: responsibility of the caller to make sure that the packet type, command, * WARNING: data and data byte count are valid for the transaction requested. Failure * WARNING: to follow the rules will make this routine fail and CRASH the system. * * Input: * a0.l Pointer to Base address table * * d0.l = High word PACKET Command * Low word PACKET Type * * d1.l = Up to four bytes of data to send * Long word data byte assigment = byte 4, byte 3, byte 2, byte 1 * Byte 1 sent out first * * d2.l = Byte count to send. (0-4 bytes) * Byte count > 4 will send four bytes only * * Output: d0.w $0000 if call succeeded, Nonzero if failed * * d1.l high word = flags, low word packet type returned by Cuda * * Destroys: D2.l, D3.l, D4.l, A5.l, A4.l, A1.l * ************************************************************************************************************ SendCudaCmd movea.l DecoderInfo.VIA1Addr(a0),a1 ; get VIA 1 base address move.l #((MaxTout<<16) OR MaxRetries),d4 ; number of retries before giving up with Cuda eieioSTP btst.b #TIP,vBufB(a1) ; check for a transaction in progress eieioSTP bne.s @AllOK @Timeout eieioSTP ori.b #((1< move.l #0001,d6 ; d6.l must be nonzero bra.s * VsrIrq move.l d4,-(sp) move $d00,d4 divu #10,d4 dbra.w d4,* move.l (sp)+,d4 eieioSTP tst.b vSR(a1) ; clear the interrupt nop eieioSTP btst.b #TReq,vBufB(a1) ; exit with abort status nop eieioSTP AbortReq rts5 ;-------------------------------------------------------------------------- ; DumpAbort 9774 This routine will read all the data for an abort transaction and ; discard it. When done it will jump back to SendNopCmd entry point ; to retry our command. This command will eventually complete... Export RealAbort RealAbort eieioSTP bclr.b #SRdir,vACR(a1) ; shift in nop eieioSTP ori.b #((1<